题目:
https://www.lydsy.com/JudgeOnline/problem.php?id=2733
题解:
建n棵动态开点的权值线段树,然后边用并查集维护连通性,边合并线段树维护第k重要。
其实实现还是很简单的。。
代码:
1 #include<bits/stdc++.h>
2
3 using namespace std;
4
5 const int maxn=300010;
6 int fa[maxn],root[maxn],n,m,g[maxn],f[maxn],id;
7 char ch[3];
8
9 struct Tr{
10 int lt,rt,num;
11 int ch[2];
12 }tree[maxn<<3];
13
14 void update(int now){
15 tree[now].num=tree[tree[now].ch[0]].num+tree[tree[now].ch[1]].num;
16 }
17
18 int merge(int now,int last){
19 if(!now) return last;
20 else if(!last) return now;
21 if(tree[now].num<tree[last].num) swap(now,last);
22 tree[now].ch[0]=merge(tree[now].ch[0],tree[last].ch[0]);
23 tree[now].ch[1]=merge(tree[now].ch[1],tree[last].ch[1]);
24 update(now);return now;
25 }
26
27 int ffa(int x){
28 return fa[x]==x?x:fa[x]=ffa(fa[x]);
29 }
30
31 void connect(int u,int v){
32 int fu=ffa(u),fv=ffa(v);
33 if(fu!=fv) root[fu]=merge(root[fu],root[fv]),fa[fv]=fu;
34 }
35
36 void build(int &now,int w,int lt,int rt){
37 now=++id;
38 tree[now].lt=lt,tree[now].rt=rt;
39 if(lt==rt){ tree[now].num=1;return ;}
40 int mid=lt+rt>>1;
41 if(w<=mid) build(tree[now].ch[0],w,lt,mid);
42 else build(tree[now].ch[1],w,mid+1,rt);
43 update(now);
44 }
45
46 int ask(int now,int k){
47 if(tree[now].num<k) return -1;if(tree[now].lt==tree[now].rt) return tree[now].lt;
48 if(tree[tree[now].ch[0]].num>=k) return ask(tree[now].ch[0],k);
49 else return ask(tree[now].ch[1],k-tree[tree[now].ch[0]].num);
50 }
51
52 int main(){
53 //freopen("1.in","r",stdin);
54 scanf("%d%d",&n,&m);
55 for(int i=1;i<=n;i++) fa[i]=i;
56 for(int i=1;i<=n;i++){
57 scanf("%d",&g[i]);f[g[i]]=i;
58 build(root[i],g[i],1,n);
59 } int u,v,x,y,tt;
60 for(int i=1;i<=m;i++) scanf("%d%d",&u,&v),connect(u,v);
61 scanf("%d",&m);
62 for(int i=1;i<=m;i++){
63 scanf("%s%d%d",ch,&x,&y);
64 if(ch[0]=='Q')
65 tt=ask(root[ffa(x)],y),printf("%d
",tt==-1?-1:f[tt]);
66 else connect(x,y);
67 }
68 return 0;
69 }