1 条题解

  • 0
    @ 2025-8-24 21:23:59

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar SovietPower✨
    因你而起的一泓喜悲 权当年轻 留个纪念

    搬运于2025-08-24 21:23:58,当前版本为作者最后更新于2017-06-28 17:00:09,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    109ms,最快的了吧

    题意肯定是求最小生成树了,问题在于怎样减少时间消耗。

    主要思路是逆序求解,因为这样可以尽可能地减少使用Kruskal的次数,时间复杂度自然就降下来了

    每次Kruskal记录用到的边,如果(每一周)删掉了一条用到的边,那自然需要重新求一遍最小生成树;如果没用到,那就不用求了,直接赋值为上一个结果。

    如果有一周出现了-1,那它继续删边肯定更不联通了,所以之后所有答案都是-1,break就好

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=205,M=6005;
    
    int n,w,Enum,H[M<<1],fa[N];
    long long Ans[M];
    bool use[M<<1],cannot[M<<1];//use:记录最近一次求最小生成树用到的边   cannot[ i ]:i这条边不能再用了(已删)
    struct Edge
    {
        int fr,to,nxt,val,id;
        bool operator <(const Edge &a)const
        {
            return val<a.val;
        }
    }e[M<<1];
    
    int read()
    {
        int now=0;bool f=false;char c=getchar();
        while(c>'9'||c<'0')
        {
            if(c=='-')f=1;
            c=getchar();
        }
        while(c>='0'&&c<='9')now=(now<<3)+(now<<1)+c-'0',c=getchar();
        return f?-now:now;
    }
    
    void AddEdge(int u,int v,int w)
    {
        e[++Enum].to = v;
        e[Enum].fr = u;
        e[Enum].nxt = H[u];
        e[Enum].val = w;
        H[u] = Enum;
    }
    
    int Find(int x)
    {
        return x==fa[x]?x:fa[x]=Find(fa[x]);
    }
    
    long long Kruskal()
    {
        memset(use,0,sizeof use);
        for(int i=1;i<=n;i++)
          fa[i]=i;
        int k=0;
        long long tot=0;
        for(int i=1;i<=Enum;i++)
        {
            if(cannot[e[i].id]) continue;
            int r1=Find(e[i].fr),r2=Find(e[i].to);
            if(r1!=r2)
            {
                ++k;tot+=e[i].val;
                use[e[i].id]=1;//printf("use:%d\n",e[i].id);
                fa[r1]=r2;
            }
            if(k==n-1)
              break;
        }
        return k==n-1?tot:-1;
    }
    
    int main()
    {
        n=read(),w=read();
        for(int a,b,c,i=1;i<=w;i++)
    //      Fr[i]=read(),To[i]=read),Val[i]=read();
          a=read(),b=read(),c=read(),AddEdge(a,b,c),e[i].id=i;
        sort(e+1,e+Enum+1);
        Ans[w]=Kruskal();
        for(int i=w-1;i;i--)
        {
            cannot[i+1]=1;//printf("cannot:%d\n",i+1);
            if(use[i+1])
              Ans[i]=Kruskal();//printf("OK\n");
            else
              Ans[i]=Ans[i+1];
            if(Ans[i]==-1)//不连通,那之后的肯定也不连通 
            {
                for(int j=1;j<i;j++)
                  Ans[j]=-1;
                break;
            }
        }
        for(int i=1;i<=w;i++)
          printf("%lld\n",Ans[i]);
        return 0;
    }
    
    • 1

    信息

    ID
    338
    时间
    1000ms
    内存
    125MiB
    难度
    4
    标签
    递交数
    0
    已通过
    0
    上传者