如题。
方法一:LCT!细节挺多,略。
方法二:如题(废话。。)
如果照传统的方法,比如1,2,3在一起要把1删掉,要保证1的爸爸和2,3以后不一样,如果1不是根节点就直接$fa[1]=1$,否则需要改所有的儿子。
上面的问题在于删掉根节点的操作过于冗杂,也就是说想一个办法使得1-n中没有一个点作为根节点,那就新申请n+1-2n做1-n的根,这样就不可能会有谁做根节点。
慢着,如果某个点被删掉,他的爸爸要变,又不能变成自己,咋整?再申请!
以下是:给一个图,保证每个点度数不超过10,一开始所有点都下线,每次可以选一个点上线和周围上线的点所在集合合并,或者选一个点下线,或者查某个点所在集合的大小。
1 #include<string.h> 2 #include<stdlib.h> 3 #include<stdio.h> 4 #include<math.h> 5 #include<algorithm> 6 //#include<queue> 7 //#include<iostream> 8 using namespace std; 9 10 int n,m,q; 11 #define maxn 200011 12 struct Edge{int to,next;}edge[maxn<<1]; int first[maxn],le=2; 13 void in(int x,int y) {Edge &e=edge[le]; e.to=y; e.next=first[x]; first[x]=le++;} 14 void insert(int x,int y) {in(x,y); in(y,x);} 15 16 int ufs[maxn*3],size[maxn*3]; bool live[maxn]; 17 int find(int x) {return x==ufs[x]?x:(ufs[x]=find(ufs[x]));} 18 void Union(int x,int y) 19 { 20 x=find(x),y=find(y); if (x==y) return; 21 ufs[x]=y; size[y]+=size[x]; 22 } 23 24 int main() 25 { 26 scanf("%d%d%d",&n,&m,&q); 27 for (int i=1,x,y;i<=m;i++) 28 { 29 scanf("%d%d",&x,&y); 30 insert(x,y); 31 } 32 for (int i=1;i<=n;i++) ufs[i]=i+n,ufs[i+n]=i+n,size[i+n]=1; int tot=n+n; 33 char id;int x; 34 while (q--) 35 { 36 while ((id=getchar())!='i' && id!='q' && id!='o'); scanf("%d",&x); 37 if (id=='i') 38 { 39 live[x]=1; 40 for (int i=first[x];i;i=edge[i].next) 41 { 42 const Edge &e=edge[i]; if (!live[e.to]) continue; 43 Union(x,e.to); 44 } 45 } 46 else if (id=='o') 47 { 48 live[x]=0; int y=find(x); size[y]--; 49 ufs[x]=++tot; ufs[tot]=tot; size[tot]=1; 50 } 51 else 52 { 53 x=find(x); 54 printf("%d ",size[x]); 55 } 56 } 57 return 0; 58 }