zoj 3261 逆向并查集
很明显是逆向的并查集,建立边再销毁,思路也很巧妙的逆向思考~
如果正着一一销毁,相当于倒着一一建边。
所以保存Q次提问,最后倒着来一一建边。
在此之前先把没有销毁的边全部建好~细节power能量注意一下~
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <map> 2 #include <stdio.h> 3 #include <string.h> 4 #include <vector> 5 #include <iostream> 6 using namespace std; 7 8 const int N=50005; 9 int n,m,i,j; 10 int power[N]; 11 int father[N]; 12 int g[N][3]; 13 int ans[N],cnt; 14 map<pair<int,int>,int>M; 15 16 int find(int x){ 17 if(x!=father[x]){ 18 father[x]=find(father[x]); 19 } 20 return father[x]; 21 } 22 23 void merge(int a,int b){ 24 int x=find(a); 25 int y=find(b); 26 if(x==y) return ; 27 if(power[x]>power[y]||(power[x]==power[y]&&x<y)) father[y]=x; 28 else father[x]=y; 29 } 30 int main(){ 31 char ch[10]; 32 int a,b,q,k=0; 33 while(scanf("%d",&n)!=EOF){ 34 M.clear(); 35 for(i=0;i<n;i++) 36 scanf("%d",&power[i]), 37 father[i]=i; 38 39 scanf("%d",&m); 40 for(i=0;i<m;i++){ 41 scanf("%d%d",&a,&b); 42 if(a>b) a^=b^=a^=b; 43 M[make_pair(a,b)]=1; 44 } 45 46 scanf("%d",&q); 47 for(i=0;i<q;i++){ 48 scanf("%s",ch); 49 if(ch[0]=='q'){ 50 scanf("%d",&a); 51 g[i][0]=0; 52 g[i][1]=a; 53 }else{ 54 scanf("%d%d",&a,&b); 55 g[i][0]=1; 56 g[i][1]=a; 57 g[i][2]=b; 58 if(a>b) a^=b^=a^=b; 59 M[make_pair(a,b)]=0; 60 } 61 } 62 63 map<pair<int,int>,int>::iterator it; 64 for(it=M.begin();it!=M.end();it++){ 65 if(it->second){ 66 pair<int,int> tmp=it->first; 67 merge(tmp.first,tmp.second); 68 } 69 } 70 cnt=0; 71 while(q--){ 72 if(g[q][0]){ 73 merge(g[q][1],g[q][2]); 74 }else{ 75 a=g[q][1]; 76 int x=find(a); 77 if(power[x]==power[a]) ans[cnt++]=-1; 78 else ans[cnt++]=x; 79 } 80 } 81 if(k++) puts(""); 82 while(cnt--) 83 printf("%d\n",ans[cnt]); 84 } 85 return 0; 86 }