题目大意:给定一个无向图以及n个点的排名,多次连接一条边,多次求某个点所在联通块中排名第k小的点的编号
初始对于每个点建立一棵只有一个节点的Treap,然后每次连接两个点,利用并查集找到两个点的根节点,将size较小的Treap暴力拆解插入大的中,然后将小的并查集合并到大的中
今天下午各种脑残,一个小小的Treap改了不下10遍0.0 快去喝脑白金0.0
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 100100 using namespace std; struct abcd{ abcd *ls,*rs; int num,key; int siz; abcd(int x); void Maintain(); }*null=new abcd(0),*tree[M]; int n,m,q,a[M]; int fa[M],siz[M]; abcd :: abcd(int x) { ls=rs=null; num=x; if(!x) key=0,siz=0; else key=rand(),siz=1; } void abcd :: Maintain() { siz=ls->siz+rs->siz+1; } void Zig(abcd *&x) { abcd *y=x->ls; x->ls=y->rs; y->rs=x; x=y; x->rs->Maintain(); x->Maintain(); } void Zag(abcd *&x) { abcd *y=x->rs; x->rs=y->ls; y->ls=x; x=y; x->ls->Maintain(); } void Insert(abcd *&x,abcd *y) { if(x==null) { x=y; x->ls=x->rs=null; x->Maintain(); return ; } if(y->num<x->num) { Insert(x->ls,y); if(x->ls->key>x->key) Zig(x); } else { Insert(x->rs,y); if(x->rs->key>x->key) Zag(x); } x->Maintain(); } void Decomposition(abcd *x,int y) { if(x==null) return ; Decomposition(x->ls,y); Decomposition(x->rs,y); Insert(tree[y],x); } int Rank(abcd *x,int k) { if(x==null) return 0; int temp=x->ls->siz; if(k<=temp) return Rank(x->ls,k); k-=temp; if(k==1) return x->num; --k; return Rank(x->rs,k); } int Find(int x) { if(!fa[x]) fa[x]=x,siz[x]=1; if(fa[x]==x) return fa[x]=x; return fa[x]=Find(fa[x]); } void Merge(int x,int y) { int fx=Find(x),fy=Find(y); if(fx==fy) return ; if(siz[fx]>siz[fy]) swap(x,y),swap(fx,fy); Decomposition(tree[fx],fy); fa[fx]=fy; siz[fy]+=siz[fx]; } int main() { int i,x,y; char p[10]; cin>>n>>m; a[0]=-1; for(i=1;i<=n;i++) scanf("%d",&x),tree[i]=new abcd(x),a[x]=i; for(i=1;i<=m;i++) scanf("%d%d",&x,&y),Merge(x,y); cin>>q; for(i=1;i<=q;i++) { scanf("%s%d%d",p,&x,&y); if(p[0]=='Q') printf("%d\n",a[Rank(tree[Find(x)],y)]); else Merge(x,y); } }
BZOJ 2733 HNOI2012 永无乡 Treap+启发式合并
原文地址:http://blog.csdn.net/popoqqq/article/details/40400633