P3224 [HNOI2012]永无乡 FHQ-Treap 启发式合并
Posted 昵称很长很长真是太好了
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3224 [HNOI2012]永无乡 FHQ-Treap 启发式合并相关的知识,希望对你有一定的参考价值。
题意:
B
x
y
B\\ x\\ y
B x y 表示在岛
x
x
x 与岛
y
y
y 之间修建一座新桥。
Q x k Q\\ x\\ k Q x k 表示询问当前与岛 x x x 连通的所有岛中第 k k k 重要的是哪座岛,即所有与岛 x x x 连通的岛中重要度排名第 k k k 小的岛是哪座,请你输出那个岛的编号。
题解:
一眼题,用并查集维护一下连通块,平衡树合并时用启发式合并,合并最多也就
n
l
o
g
n
nlogn
nlogn次,总时间复杂度位
O
(
n
l
o
g
n
2
)
O(nlogn^2)
O(nlogn2)
就是写代码的时候跟失了智一样,忘加一句话多调试了三小时,愚不可及
代码:
#include<bits/stdc++.h>
#define endl '\\n'
using namespace std;
const int maxn=5e5+10;
int a[maxn];
int f[maxn];
int ifind(int x){
if(x==f[x]) return x;
return f[x]=ifind(f[x]);
}
mt19937 rnd(233);
struct FHQ{
int root[maxn],cnt;
int ls[maxn],rs[maxn],val[maxn],key[maxn],siz[maxn];
int newnode(int vals){
val[++cnt]=vals;
key[cnt]=rnd();
siz[cnt]=1;
return cnt;
}
void updata(int node){
siz[node]=siz[ls[node]]+siz[rs[node]]+1;
}
void spilt_val(int node,int vals,int &x,int &y){
if(!node){
x=y=0;
return;
}
if(val[node]<=vals){
x=node;
spilt_val(rs[node],vals,rs[node],y);
}
else{
y=node;
spilt_val(ls[node],vals,x,ls[node]);
}
updata(node);
}
int mer(int x,int y){
if(!x||!y) return x+y;
if(key[x]>key[y]){
rs[x]=mer(rs[x],y);
updata(x);
return x;
}
else {
ls[y]=mer(x,ls[y]);
updata(y);
return y;
}
}
void mer_node(int tree,int nd){
int x,y;
spilt_val(root[tree],val[nd],x,y);
root[tree]=mer(mer(x,nd),y);
}
int x;
void dfs(int node){
if(!node) return ;
dfs(ls[node]);
dfs(rs[node]);
ls[node]=rs[node]=0; //!!摘掉以后记得清空
siz[node]=1;
mer_node(x,node);
}
// void lrd(int node){
// if(!node) return;
// //cout<<"dfs "<<node<<endl;
// lrd(ls[node]);
// lrd(rs[node]);
// }
int merge_tree(int a,int b){
if(siz[root[a]]<siz[root[b]]) swap(a,b); //启发式,把b合并到a上
x=a;
dfs(root[b]);
return x;
}
int get_num(int tree,int rk){
int node=root[tree];
if(siz[node]<rk) return -1;
while(node){
if(siz[ls[node]]+1==rk) break;
else if(siz[ls[node]]>=rk) node=ls[node];
else{
rk-=siz[ls[node]]+1;
node=rs[node];
}
}
return node;
}
}fhq;
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
for(int i=1;i<=100000;i++){
f[i]=i;
}
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
fhq.root[i]=fhq.newnode(a[i]);
}
for(int i=1;i<=m;i++){
int x,y;
cin>>x>>y;
int dx=ifind(x);
int dy=ifind(y);
if(dx!=dy){
int now=fhq.merge_tree(dx,dy);
f[dx]=now;
f[dy]=now;
}
}
int q;
cin>>q;
while(q--){
char opt;
cin>>opt;
if(opt=='Q'){
int x,k;
cin>>x>>k;
x=ifind(x);
cout<<fhq.get_num(x,k)<<endl;
}
else{
int x,y;
cin>>x>>y;
int dx=ifind(x);
int dy=ifind(y);
if(dx!=dy){
int now=fhq.merge_tree(dx,dy);
f[dx]=now;
f[dy]=now;
}
}
}
}
以上是关于P3224 [HNOI2012]永无乡 FHQ-Treap 启发式合并的主要内容,如果未能解决你的问题,请参考以下文章
[BZOJ2733][P3224][HNOI2012]永无乡[平衡树+启发式合并+并查集]
P3224 [HNOI2012]永无乡 FHQ-Treap 启发式合并
P3224 [HNOI2012]永无乡 FHQ-Treap 启发式合并