并查集删点就是弄个id记录当前点的id,删除的时候将id设为新的id,忽略原来的id,当然还要注意去改变原来集合需要维护的性质比如元素个数等等。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) using namespace std; typedef long long ll; const int maxn=1000100; const int INF=1e9+10; int n,m; int fa[maxn],id[maxn]; int cnt[maxn];ll sum[maxn]; int op,u,v; int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); } void Union(int u,int v) { int x=find(id[u]),y=find(id[v]); if(x==y) return; fa[x]=y; cnt[y]+=cnt[x]; sum[y]+=sum[x]; } void Remove(int u) { int x=find(id[u]); cnt[x]--; sum[x]-=u; id[u]=++n; fa[id[u]]=id[u]; cnt[id[u]]=1; sum[id[u]]=u; } int main() { freopen("in.txt","r",stdin); while(cin>>n>>m){ REP(i,1,n) fa[i]=i,id[i]=i,cnt[i]=1,sum[i]=i; REP(i,1,m){ scanf("%d",&op); if(op==1) scanf("%d%d",&u,&v),Union(u,v); else if(op==2){ scanf("%d%d",&u,&v); int x=find(id[u]),y=find(id[v]); if(x==y) continue; Remove(u); Union(u,v); } else{ scanf("%d",&u); int x=find(id[u]); printf("%d %lld\n",cnt[x],sum[x]); } } } return 0; }
这题的坑点在于第二个操作,把u放在u所在集合的时候直接忽略,而不是把u拿出来。
时间: 2024-10-14 07:19:10