2 条题解

  • 2
    @ 2023-5-13 16:44:53

    写的不好,欢迎提出改进👀️

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int MAXI=4e5+4;
    int f[MAXI],head[MAXI],h[MAXI],ans[MAXI],En=0;
    bool e[MAXI];            
    int find(int x)
    {
        if(x!=f[x]) f[x]=find(f[x]); 
        return f[x];
    }
    struct edge
    {
        int from;
        int to;                 
        int next;
    }a[MAXI];
    void insert(int u,int v)
    {                             
        a[En].from=u;
        a[En].next=head[u];    
        a[En].to=v;
        head[u]=En;
        En++;
    }
    int main()
    {
        int n,m,k,x,y,tot,i,u;
        cin>>n>>m;
        for(i=0;i<n;++i) 
        {
            f[i]=i;
            head[i]=-1;
        }
        for(i=0;i<m;++i)
        {
            cin>>x>>y;
            insert(x,y);insert(y,x);         
        }
        cin>>k;
        tot=n-k;     
        for(i=1;i<=k;i++)
        {
            cin>>x;
            e[x]=true;    
            h[i]=x;
        }
        for(i=0;i<2*m;i++)
        {
            if(e[a[i].from]==false&&e[a[i].to]==false) 
            {
                if(find(a[i].from)!=find(a[i].to))    
                {
                    tot--;            
                    f[find(a[i].from)]=f[find(a[i].to)];
                }
            }
        }
        ans[k+1]=tot;  
        for(int t=k;t>=1;t--) 
        {
            u=h[t]; 
            tot++;   
            e[u]=false; 
            for(i=head[u];i!=-1;i=a[i].next)
            {
                if(e[a[i].to]==false&&f[find(u)]!=f[find(a[i].to)]) 
                {
                    tot--;  //合并 
                    f[find(a[i].to)]=f[find(u)]; 
                }
            }
            ans[t]=tot; 
        }
        for(i=1;i<=k+1;++i) cout<<ans[i]<<endl;
        return 0;
    }
    
    • @ 2023-5-21 16:25:07
      运用这个代码,请注意!
      
      一定要将一开始的编译器(C(O2))改为(C++98)
      

      不然会出现

      致命错误:iostream no such file or directory
      

      这是因为C中没有iostream,下面是解决办法

      1.将C(O2)改为C++98/C++17/C++11
      
      2.如果用的是自己的编译器,将后缀名(.C)改为(.cpp)再重新编译
      
  • 1
    @ 2023-5-11 22:08:51

    本题的目的是各个时间求联通块的个数,从最后时刻往前做,并查集的初始状态即被破坏后的图。

    主要思想是,并查集中处于一个联通块的祖先结点相等,当任意祖先不同两个联通块联通时,联通块会减少一个(同时当破坏的被恢复时会增加一个),通过这种操作可以知道目前有多少个联通块。

    而本题只需要知道是否在一个并查集中就可知道是否增删联通块了,因此核心算法不是很难。

    具体操作说明附在代码里

    #include<bits/stdc++.h>
    using namespace std;
    const int N=4000005,M=2000005;
    struct node{
    	int y,next;
    }b[2*M];
    struct node1{
    	int x,y;
    }a[M];
    int n,m,k,s,t,mm,head[N],fa[N],tot,f[N],c[N],ans,g[N];
    //f 0 未摧毁 1 摧毁 
    void add(int s,int t){
    	b[++tot].y=t;
    	b[tot].next=head[s];
    	head[s]=tot;
    }
    int getfa(int x){
    	if (fa[x]==x) return x;
    	fa[x]=getfa(fa[x]);
    	return fa[x];
    }
    void link(int s,int t){
    	int ss=getfa(s);
    	int tt=getfa(t);
    	if (ss!=tt){
    		ans--;
    		fa[ss]=tt;
    	}
    }
    int main()
    {
    	cin>>n>>mm;
    	for (int i=1;i<=n;++i)
    		fa[i]=i;
    	for (int i=1;i<=mm;++i){
    		cin>>s>>t;
    		++s;++t;
    		a[i].x=s;a[i].y=t;//保存所有边 
    		add(s,t);add(t,s);
    	}	
    	cin>>m;
    	for (int i=1;i<=m;++i){
    		cin>>c[i];
    		c[i]++;
    		f[c[i]]=1;
    	}
    	ans=n-m;//初始答案为总星球数-被破坏的星球数 
    	for (int i=1;i<=mm;++i){
    		if (f[a[i].x]==0&&f[a[i].y]==0) link(a[i].x,a[i].y);
    		//遍历所有边,如果两条边都存在,则合并并查集 
    	}
    	g[m+1]=ans;//记录答案 
    	for (int i=m;i>=1;--i){
    		f[c[i]]=0;
    		ans++;
    		for (int k=head[c[i]];k;k=b[k].next){
    			int y=b[k].y;
    			if (f[y]==0) link(c[i],y);
    			//对应边存在,则合并并查集 
    		}
    		g[i]=ans;
    	}
    	for (int i=1;i<=m+1;++i)
    		cout<<g[i]<<endl;
    }
    
    • 1

    信息

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