题意:有一些点,现对这些点进行操作,输入“M a,b”代表a,b是一个集合,“S a ”表从集合中删除a点,最后输出有几个集合?
这个题涉及到了一个神奇的删点操作,而且删点只删一个点,以前是一个集合的不变,所以倒着处理也会很麻烦,那怎么办呢,显然我们删除一个点的时候要更改指针,使这个点从原图中被摘除,但是我们要删除的如果就是根节点怎么办?思考一下如何处理?
没错,没有办法处理对不对?那很简单,我们绕过这道坎,我们就当所有合法的点都不是根节点,怎么处理呢?可以虚设一个根节点,然后删除任意一个点时,只需给他新建一个父节点即可,和原图没有任何影响,只不过牺牲了一些空间利用率,就把这道神题解决了,下面上代码:
1 //灯为谁点,脂为谁添? 2 #include<iostream> 3 #include<cstring> 4 #include<string> 5 #include<queue> 6 #include<cmath> 7 #include<cstdio> 8 #include<cstdlib> 9 #include<queue> 10 using namespace std; 11 const int MAXN=1200005; 12 int father[MAXN],n,m,id,k=0,s,w; 13 char ch[5];bool vis[MAXN]; 14 int get(int x){return father[x]==x?x:father[x]=get(father[x]);} 15 void take(){ 16 for(int i=0;i<n;i++) father[i]=i+n; 17 for(int i=n;i<=n+n+m;i++) father[i]=i; 18 } 19 void merge(int x,int y){x=get(x);y=get(y);if(x!=y) father[x]=y;} 20 void del(int x){father[x]=id++;}//给这个点换一个新的父节点,就好了; 21 int main(){ 22 while(~scanf("%d%d",&n,&m)&&(n||m)){ 23 id=n+n;take(); 24 while(m--){ 25 scanf("%s",ch); 26 if(ch[0]=='M'){ 27 int x,y;scanf("%d%d",&x,&y);merge(x,y); 28 } 29 else{ 30 int z;scanf("%d",&z);del(z); 31 } 32 } 33 int ans=0;memset(vis,0,sizeof(vis)); 34 for(int i=0;i<n;i++){ 35 int x=get(i);if(!vis[x]) vis[x]=1,ans++; 36 } 37 printf("Case #%d: %d\n", ++k, ans); 38 } 39 } 40 //任谁来笑我太疯癫!