题意
给出 \(q\) 个操作。
- 将 \(u\) 和 \(v\) 连边。
- 问 \(u\) 所在的连通块中编号第 \(k\) 大的点。
思路
连通块很容易想到并查集,求第 \(k\) 大可以用平衡树(虽然赛时没看到 \(k\le 10\)),合并时将信息从将小的连通块合并到大的连通块,这样可以减少时间复杂度。
什么?你不会写平衡树?直接套 pbds 库中的 tree 就可以了(具体见代码)。
代码
#include<bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;
using namespace __gnu_pbds;//注意使用pbds库时需要加上头文件和命名空间
struct bal_tree{
tree<int,null_type,less_equal<int>,rb_tree_tag,tree_order_statistics_node_update> t;//使用tree的方式,具体参数可以上网查,不会的直接复制就可以了
void insert(int x){t.insert(x);}
void del(int x){t.erase(t.upper_bound(x));}
int rnk(int x){return t.order_of_key(x)+1;}
int find_rnk(int x){return *t.find_by_order(x-1);}
int upper_bound(int x){return *t.upper_bound(x);}
int lower_bound(int x){return *t.lower_bound(x);}
}t[200005];
int n,q,f[200005];
int find(int x){
if(f[x]!=x) f[x]=find(f[x]);
return f[x];
}
signed main(){
cin>>n>>q;
for(int i=1;i<=n;i++)
f[i]=i,t[i].insert(i);
while(q--){
int op,x,y;
cin>>op>>x>>y;
if(op==1){
int p1=find(x),p2=find(y);
if(p1!=p2){
if(t[p1].t.size()>t[p2].t.size())
swap(p1,p2);
f[p1]=p2;
for(int v:t[p1].t)
t[p2].insert(v);
t[p1].t.clear();
}
}
else{
x=find(x);
if(t[x].t.size()<y)
cout<<-1<<endl;
else
cout<<t[x].find_rnk(t[x].t.size()-y+1)<<endl;//注意是第k大
}
}
return 0;
}
标签:p2,p1,return,int,题解,ABC372E,tree,Components,find
From: https://www.cnblogs.com/WuMin4/p/18427157