题目链接:http://icpc.njust.edu.cn/Problem/Hdu/1272/
题目要求支持两种操作,一种是合并,一种是去除一个点与其他所有点的关系,但是其他的点显然是保持着原有的关系的,涉及关系的问题我们首要想到的就是并查集。删关系的操作我们可以让这个结点指向一个从没有用过的结点就行,但是如果这个结点是某棵树的根的话就会造成这棵树上的其他结点还是指向了要删除的结点。所以我们需要建立虚拟结点,使0-n-1编号的结点开始的时刻不是指向其本身,这样删除结点就直接使要删除的结点指向一个新的结点就可以,合并和删除都基本是常数复杂度。有一点要注意的就是在并查集中所有的结点都是有父亲结点的,所以最多有m次删除操作后指向的点初始化的时候要指向其本身。如果不设置的话find(x)将永远也不会获取到x的father。
代码如下:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef unsigned int ui; 4 typedef long long ll; 5 typedef unsigned long long ull; 6 #define pf printf 7 #define mem(a,b) memset(a,b,sizeof(a)) 8 #define prime1 1e9+7 9 #define prime2 1e9+9 10 #define pi 3.14159265 11 #define lson l,mid,rt<<1 12 #define rson mid+1,r,rt<<1|1 13 #define scand(x) scanf("%llf",&x) 14 #define f(i,a,b) for(int i=a;i<=b;i++) 15 #define scan(a) scanf("%d",&a) 16 #define mp(a,b) make_pair((a),(b)) 17 #define P pair<int,int> 18 #define dbg(args) cout<<#args<<":"<<args<<endl; 19 #define inf 0x3f3f3f3f 20 const int maxn=1300000; 21 int n,m,t; 22 int aa=0; 23 int a,b; 24 set<int> s; 25 int index; 26 int f[maxn]; 27 void init() 28 { 29 f(i,0,n-1)f[i]=i+n; 30 f(i,n,2*n+m)f[i]=i;//至多删除maxn个结点, 31 index=2*n; 32 s.clear(); 33 } 34 int find(int x) 35 { 36 if(x==f[x])return x; 37 return f[x]=find(f[x]); 38 } 39 void Union(int x,int y) 40 { 41 int fx=find(x); 42 int fy=find(y); 43 if(fx==fy)return; 44 else f[fx]=fy; 45 } 46 int main() 47 { 48 //freopen("input.txt","r",stdin); 49 //freopen("output.txt","w",stdout); 50 std::ios::sync_with_stdio(false); 51 char tmp[5]; 52 while(scanf("%d %d",&n,&m)==2&&(n+m)) 53 { 54 aa++; 55 init(); 56 f(i,1,m) 57 { 58 scanf(" %s",tmp); 59 if(tmp[0]=='M') 60 { 61 scan(a); 62 scan(b); 63 Union(a,b); 64 } 65 if(tmp[0]=='S') 66 { 67 scan(a); 68 f[a]=index++; 69 } 70 } 71 f(i,0,n-1)s.insert(find(i)); 72 pf("Case #%d: %d ",aa,s.size()); 73 } 74 return 0; 75 }