【BZOJ】2733: [HNOI2012]永无乡

【题意】给定n个岛屿和排名,q次操作,连接两个岛屿或查询岛屿所在连通块第k小。

【算法】平衡树(treap)||线段树合并

对于每个连通块维护排名树,启发式合并(将size较小的树一一拆出来加入另一棵树)。

复杂度O(n log2n)。

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<stack>
using namespace std;
const int maxn=100010;
struct tree{int l,r,rnd,sz,num,id;}t[maxn*2];
stack<int>s;
int rank[maxn],fa[maxn],root[maxn],n,m;
int read(){
    char c;int s=0,t=1;
    while(!isdigit(c=getchar()))if(c=='-')t=-1;
    do{s=s*10+c-'0';}while(isdigit(c=getchar()));
    return s*t;
}
void up(int k){t[k].sz=t[t[k].l].sz+1+t[t[k].r].sz;}
void rturn(int &k){
    int o=t[k].l;
    t[k].l=t[o].r;
    t[o].r=k;
    up(k);up(o);
    k=o;
}
void lturn(int &k){
    int o=t[k].r;
    t[k].r=t[o].l;
    t[o].l=k;
    up(k);up(o);
    k=o;
}
void insert(int &k,int x){
    if(!k){
        k=s.top();s.pop();
        t[k].rnd=rand();t[k].num=rank[x];
        t[k].sz=1;t[k].l=t[k].r=0;t[k].id=x;
        return;
    }
    t[k].sz++;
    if(rank[x]<t[k].num){
        insert(t[k].l,x);
        if(t[t[k].l].rnd<t[k].rnd)rturn(k);
    }
    else{
        insert(t[k].r,x);
        if(t[t[k].r].rnd<t[k].rnd)lturn(k);
    }
}
int getfa(int x){return fa[x]==x?x:fa[x]=getfa(fa[x]);}
void dfs(int k,int &x){
    if(!k)return;
    s.push(k);
    int L=t[k].l,R=t[k].r;
    insert(x,t[k].id);
    dfs(L,x);dfs(R,x);
}
void merge(int x,int y){
    x=getfa(x);y=getfa(y);
    if(x==y)return;
    if(t[root[x]].sz<t[root[y]].sz)swap(x,y);
    fa[y]=x;
    dfs(root[y],root[x]);
}
int find(int k,int x){
    if(x==t[t[k].l].sz+1)return t[k].id;
    else if(x<t[t[k].l].sz+1)return find(t[k].l,x);
    else return find(t[k].r,x-t[t[k].l].sz-1);
}
int main(){
    srand(233);
    n=read();m=read();
    for(int i=1;i<=n;i++)rank[i]=read();
    for(int i=n;i>=1;i--)s.push(i);
    for(int i=1;i<=n;i++)insert(root[i],i);
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int i=1;i<=m;i++){
        int x=read(),y=read();
        merge(x,y);
    }
    int Q=read();
    char ch[10];
    for(int i=1;i<=Q;i++){
        scanf("%s",ch);
        int x=read(),y=read();
        if(ch[0]=='B')merge(x,y);
        else{
            if(t[root[getfa(x)]].sz>=y)printf("%d\n",find(root[fa[x]],y));//use root[]
            else printf("-1\n");
        }
    }
    return 0;
}
View Code

 

posted @ 2017-11-27 21:01  ONION_CYC  阅读(267)  评论(0编辑  收藏  举报