本题正方向求解十分困难。但倒过来就变成了普通问题。这就是离线算法的好处之一。
只是在联合不同节点时候要总以节点能量最大且编号尽量小的做根节点。
#include <cstdio> #include <cstring> #include <iostream> #include <cctype> #include <cmath> #include <set> #include <map> #include <vector> #include <algorithm> using namespace std; #define rep(i,n) for(int i = 0;i< (n);i++) #define rep2(i,x,y) for(int (i) = (x) ; (i)< (y) ;(i)++) const int maxn = 20101; int p[maxn]; int find(int x){return p[x]==x ? x:p[x]=find(p[x]);} int w[maxn],n,m,u[maxn],v[maxn],vis[maxn]; void Union(int x,int y){ int px = find(x),py=find(y); if(px==py) return ; if(w[px]>w[py]||(w[px]==w[py]&&px<py)) p[py]=px; else p[px]=py; } struct node{ int cmd,p,x,y; node(int x=0,int y=0):x(x),y(y){} bool operator<(const node& a)const{ return x<a.x||(x==a.x&&y<a.y); } }st[50100]; map<node,int> id; vector<int> ans; int main() { int kase=0; while(scanf("%d",&n)==1){ if(kase++) printf("\n"); rep(i,n){ scanf("%d",&w[i]); } scanf("%d",&m); id.clear(); rep(i,m){ scanf("%d %d",&u[i],&v[i]); id[node(u[i],v[i])]=id[node(v[i],u[i])]=i; } memset(vis,0,sizeof(vis)); int Q; scanf("%d",&Q); rep(i,Q){ char cmd[10]; int x,y; scanf("%s",&cmd); if(cmd[0]=='q'){ scanf("%d",&x); st[i].cmd = 1; st[i].p = x; } else { scanf("%d %d",&x,&y); vis[id[node(x,y)]] = 1; st[i].cmd = 0; st[i].x=x,st[i].y=y; } } rep(i,n) p[i]=i; rep(i,m){ if(!vis[i]){ Union(u[i],v[i]); } } ans.clear(); for(int i=Q-1;i>=0;i--){ if(st[i].cmd==1){ int px = find(st[i].p); if(w[px]<=w[st[i].p]) ans.push_back(-1); else ans.push_back(px); } else { Union(st[i].x,st[i].y); } } for(int i=ans.size()-1;i>=0;i--){ printf("%d\n",ans[i]); } } return 0; }