题目链接:https://cn.vjudge.net/problem/HYSBZ-2733
题解:先用并查集统计哪些岛是相连的,然后每个块动态开权值线段树,每两个岛相连就是把两个块的权值线段树合并起来,查询就是从并查集中寻找那个块,然后查询第k大。注意:(这个题的读入字符要用字符串读入,否则会出错);
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
struct node
{
int num,l,r;
} s[maxn*40];
int tot;
void init()
{
memset(s,0,sizeof(s));
tot=0;
}
int add(int l,int r,int num)
{
s[++tot].num++;int x=tot;
if(l==r) return x;
int mid=(l+r)>>1;
if(num<=mid) s[x].l=add(l,mid,num);
else s[x].r=add(mid+1,r,num);
return x;
}
void hebing(int x,int y)
{
s[x].num+=s[y].num;
if(s[s[x].l].num==0) s[x].l=s[y].l;
else if(s[s[x].l].num&&s[s[y].l].num) hebing(s[x].l,s[y].l);
if(s[s[x].r].num==0) s[x].r=s[y].r;
else if(s[s[x].r].num&&s[s[y].r].num) hebing(s[x].r,s[y].r);
}
int query(int x,int l,int r,int k)
{
if(k<=0||k>s[x].num) return -1;
int num=s[s[x].l].num;
if(l==r) return l;
int mid=(l+r)>>1;
if(k<=num) return query(s[x].l,l,mid,k);
else return query(s[x].r,mid+1,r,k-num);
}
int a[maxn],b[maxn],pre[maxn],ll[maxn];
int fin(int x)
{
if(pre[x]==x) return x;
else return pre[x]=fin(pre[x]);
}
void pan(int u,int v)
{
u=a[u]; v=a[v];
int x=fin(u);
int y=fin(v);
if(x!=y){
if(s[ll[x]].num<s[ll[y]].num) hebing(ll[y],ll[x]),pre[x]=y;
else hebing(ll[x],ll[y]),pre[y]=x;
}
}
int main()
{
int n,m;
scanf("%d %d",&n,&m);init();b[0]=-1;
for(int i=1; i<=n; i++) scanf("%d",&a[i]),b[a[i]]=i;
for(int i=1; i<=n; i++) pre[i]=i;
for(int i=1; i<=n; i++) ll[i]=add(1,n,i);
int u,v,q;
char ii[10];
for(int i=1; i<=m; i++)
{
scanf("%d %d",&u,&v);
pan(u,v);
}
scanf("%d",&q);
while(q--)
{
scanf("%s %d %d",ii,&u,&v);
if(ii[0]=='B')
{
pan(u,v);
}
else
{
int x=fin(a[u]);
printf("%d\n",b[max(query(ll[x],1,n,v),0)]);
}
}
return 0;
}
/*
5 1
4 3 2 5 1
1 2
7
Q 3 2
Q 2 1
B 2 3
B 1 5
Q 2 1
Q 2 4
Q 2 3
*/