题目描述
这不是个链接
思路分析
- 这题线段树合并巨好写啊(
我是不会告诉你其实是因为我不会写平衡树的)。然后我也没怎么卡常就跑到了洛谷第一页,平衡树脸面何在
- 排名的值域很小,所以直接对每个节点开一棵关于排名的权值线段树,线段树的下标就是排名,往里面塞个数就行了,这样查询 \(k\) 小也很简单,因为这时候线段树存储的是排名位于一段区间内的点的个数,直接找个数为 \(k\) 的那个位置就好了。奥对了,每个叶子节点需要记录一下塞到这个节点的编号。
- 维护联通性时用并查集简单处理就好了,并查集和线段树同时同向合并,然后好像就没了,成功变成了线段树合并裸题
\(Code\)
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define R register
#define N 100010
using namespace std;
inline int read(){
int x = 0,f = 1;
char ch = getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
int n,m,q,fa[N],id[N<<5],tr[N<<5],ls[N<<5],rs[N<<5],root[N<<5],cnt;
char op[10];
int find(int x){
return fa[x]==x ? x : (fa[x]=find(fa[x]));
}
void modify(int &rt,int l,int r,int pos,int idx){//pos将排名转化为下标
if(!rt)rt = ++cnt;
if(l==r){
id[rt] = idx,tr[rt]++;//id记录编号
return;
}
int mid = (l+r)>>1;
if(pos<=mid)modify(ls[rt],l,mid,pos,idx);
else modify(rs[rt],mid+1,r,pos,idx);
tr[rt] = tr[ls[rt]] + tr[rs[rt]];
}
int merge(int a,int b,int l,int r){//线段树合并板子
if(!a)return b;
if(!b)return a;
if(l==r){
tr[a] += tr[b];
return a;
}
int mid = (l+r)>>1;
ls[a] = merge(ls[a],ls[b],l,mid);
rs[a] = merge(rs[a],rs[b],mid+1,r);
tr[a] = tr[ls[a]] + tr[rs[a]];
return a;
}
int query(int rt,int l,int r,int k){//查k小相当于查线段树值刚好等于k的下标(对应的编号)
if(tr[rt]<k||!rt)return 0;
if(l==r)return id[rt];
int mid = (l+r)>>1;
if(k<=tr[ls[rt]])return query(ls[rt],l,mid,k);
else return query(rs[rt],mid+1,r,k-tr[ls[rt]]);
}
int main(){
n = read(),m = read();
for(R int i = 1;i <= n;i++){
fa[i] = i;
int x = read();
modify(root[i],1,n,x,i);
}
for(R int i = 1;i <= m;i++){
int x = read(),y = read();
x = find(x),y = find(y);
fa[y] = x;
root[x] = merge(root[x],root[y],1,n);
}
q = read();
for(R int i = 1;i <= q;i++){
scanf("%s",op);
if(op[0]=='B'){
int x = read(),y = read();
x = find(x),y = find(y);
if(x==y)continue;
fa[y] = x;
root[x] = merge(root[x],root[y],1,n);
}else{
int x = read(),y = read();
x = find(x);
int ans = query(root[x],1,n,y);
if(!ans){
puts("-1");
continue;
}
else printf("%d\n",ans);
}
}
return 0;
}