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 启发式合并

P3224 [HNOI2012]永无乡 FHQ-Treap 启发式合并

洛谷 [P3224] 永无乡

HNOI2012永无乡