【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; }