题意:在一个星系中,存在n个星球,每个星球都有一定的力量值,一些星球之间有建立通道方便在有需要的时候向比自己强的星球寻求帮助,也就是力量值比寻求帮助的星球要大。在星球大战中,给出2种类型的命令:
1.query a 表示查询比a强的中最强的星球编号,如果最强编号有多个与a相连,选择编号小的那个。
2.destroy a b 表示在大战中a和b之间的通道被毁,a b断开联系。
先给出星球个数n,然后是n个星球的力量值,然后给出m,表示m条边,最后是Q个询问。
并查集可以合并,但是不能断开。所以逆向操作,一开始就处理所有的destory命令,直接到最后的状态,从后往前处理所有的命令,当遇到destory命令时在将边的两点加入集合。合并的规格是优先力量值大的星球编号为根,力量值相等优先编号小的为根。这样查询时用Find函数就可以直接找到。
询问要存储起来,边总是规定左边小,方便标记。
#include<cstdio>
#include<map>
#include<algorithm>
using namespace std;
map<pair<int,int>,bool> mp;
const int maxn = 10010;//星球个数
const int maxq = 50010;
int p[maxn],ans[5*maxn];
int f[maxn];
struct query
{
char d[20];
int a,b;
}q[maxq];
struct edge
{
int u,v;
}e[2*maxn];
int Find(int x)
{
return f[x]==x?x:f[x]=Find(f[x]);
}
void merge(int x,int y)
{
int rtx=Find(x);
int rty=Find(y);//根结点
if(rtx!=rty)
{
if(p[rtx]>p[rty])
f[rty]=rtx;
else if(p[rtx]<p[rty])
f[rtx]=rty;
else //相等按id小的
{
if(rtx<rty)
f[rty]=rtx;
else
f[rtx]=rty;
}
}
}
int main()
{
int n,fir=1;
// freopen("in.txt","r",stdin);
while(~scanf("%d",&n))
{
mp.clear();
for(int i=0;i<n;i++)f[i]=i;
for(int i=0;i<n;i++)scanf("%d",&p[i]);
int m;
scanf("%d",&m);
int x,y;
for(int i=0;i<m;i++)
{
scanf("%d%d",&x,&y);
pair<int,int> temp;
if(x>y)swap(x,y);//总是使得编号小的在右边
e[i].u=x;e[i].v=y;
temp=make_pair(x,y);
mp[temp]=0;
}
int Q;
scanf("%d",&Q);
for(int i=0;i<Q;i++)
{
scanf("%s",q[i].d);
if(q[i].d[0]=='q')
{
scanf("%d",&q[i].a);
}
else
{
pair<int,int> temp;
int u,v;
scanf("%d%d",&u,&v);
if(u>v)swap(u,v); //仍然使之左边小 方便记录 *
q[i].a=u;q[i].b=v;
temp=make_pair(q[i].a,q[i].b);
mp[temp]=1;//这条边被毁坏
}
}
for(int i=0;i<m;i++)
{
pair<int,int> temp;
temp=make_pair(e[i].u,e[i].v);
if(!mp[temp])
merge(e[i].u,e[i].v);
}
//离线
int k=0;
for(int i=Q-1;i>=0;i--)
{
if(q[i].d[0]=='q')
{
int pos=Find(q[i].a);
if(p[pos]>p[q[i].a])
ans[k++]=pos;
else
ans[k++]=-1;
}
else if(q[i].d[0]=='d')
merge(q[i].a,q[i].b);
}
if(fir)fir=0;
else printf("\n");
for(int i=k-1;i>=0;i--)
printf("%d\n",ans[i]);
}
}