题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3261
题意:N个星球,编号从0到N-1。每个星球有一个战斗力power,且这N个星球之间建有一些通道,可以相互联系,在星球大战中,一些星球的power不够强,要向和自己联通的星球中power最强的星球求救,且在星球大战中会有一些通道被损坏。然后有一些问题:destroy a b :a和b之间的通道被损坏。 query a:问a星球该向谁求救。
分析:并查集。如果一开始将星球大战之前建立的通道Union起来,以最大power的节点作为根节点,并按顺序读入数据,当遇到 query a时,就直接输出,但遇到destroy a b时,就不能简单的删掉a和b之间的边了,那么根节点的最大power值就无法维护。但如果我们先输入所有数据,即所谓的离线输入,将星球大战之后的状态作为初始状态,进行并查集的操作,遇到destroy时,就恢复a到b之间的通道,那么就很容易维护根节点的性质了,那么这题就变得很简单了。
Code:
#include <algorithm> #include <iostream> #include <cstring> #include <string> #include <cstdio> #include <vector> #include <queue> #include <cmath> #include <map> #include <set> #define eps 1e-8 #define LL long long #define Max(a,b) ((a)>(b)?(a):(b)) #define Min(a,b) ((a)<(b)?(a):(b)) using namespace std; const int inf=0x3f3f3f3f; const int maxn=10005; const int HASH=10000; int f[maxn],power[maxn],ans[maxn*5]; struct node{ int u,v; }tun[maxn<<1]; struct Node{ int a,b; char cmd[10]; }query[maxn*5]; map<int,bool>mp; int n,m,Q; void make_set(){ for(int i=0;i<n;i++) f[i]=i; } int find_set(int x){ if(x!=f[x]){ f[x]=find_set(f[x]); } return f[x]; } void Union(int x,int y){ int fx=find_set(x); int fy=find_set(y); if(fx!=fy){ if(power[fx]>power[fy]) f[fy]=fx; else if(power[fx]<power[fy]) f[fx]=fy; else { if(fx<fy) f[fy]=fx; else f[fx]=fy; } } } int main() { bool first=true; while(scanf("%d",&n)!=EOF){ for(int i=0;i<n;i++) scanf("%d",&power[i]); scanf("%d",&m); for(int i=0;i<m;i++){ scanf("%d %d",&tun[i].u,&tun[i].v); if(tun[i].u>tun[i].v) swap(tun[i].u,tun[i].v); } mp.clear(); scanf("%d",&Q); for(int i=0;i<Q;i++){ scanf("%s",query[i].cmd); if(query[i].cmd[0]=='q') scanf("%d",&query[i].a); else { scanf("%d %d",&query[i].a,&query[i].b); if(query[i].a>query[i].b) swap(query[i].a,query[i].b); mp[query[i].a*HASH+query[i].b]=true; } } make_set(); for(int i=0;i<m;i++){ if(!mp[tun[i].u*HASH+tun[i].v]) Union(tun[i].u,tun[i].v); } int cnt=0; for(int i=Q-1;i>=0;i--){ if(query[i].cmd[0]=='q') { int fa=find_set(query[i].a); if(power[fa]>power[query[i].a]) ans[cnt++]=fa; else ans[cnt++]=-1; } else Union(query[i].a,query[i].b); } if(first) first=false; else printf("\n"); for(int i=cnt-1;i>=0;i--) printf("%d\n",ans[i]); } return 0; }