首页 > 代码库 > BZOJ 2733 [HNOI2012]永无乡(启发式合并+Treap+并查集)
BZOJ 2733 [HNOI2012]永无乡(启发式合并+Treap+并查集)
【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=2733
【题目大意】
给出n个点,每个点都有自己的重要度,现在有连边操作和查询操作,
查询操作要求找出一个连通块中重要度第k的点的id
【题解】
我们用Treap维护每个连通块,对于连边操作,我们用启发式合并,
将size比较小的Treap并入size比较大的Treap,同时用并查集维护连通信息
【代码】
#include <cstdio>#include <algorithm>#include <cstring>using namespace std;const int N=100010,M=N;namespace Treap{ struct node{ int val,cnt,size,p,id;node *l,*r; node(){} node(int val,int id):val(val),id(id){p=rand();cnt=size=1;l=r=NULL;} void up(){size=cnt;if(l)size+=l->size;if(r)size+=r->size;} }*root[N],*pool[N]; int top; node *new_node(){return pool[top++];} void Initialize(){top=0;for(int i=0;i<N;i++)pool[i]=new node();} void Rotatel(node*&x){node*y=x->r;x->r=y->l;x->up();y->l=x;y->up();x=y;} void Rotater(node*&x){node*y=x->l;x->l=y->r;x->up();y->r=x;y->up();x=y;} //往treap上插入点 void Insert(node*&x,node y){ if(!x){x=new_node();(*x)=y;return;} x->size++; if(y.val==x->val){x->cnt++;return;} if(y.val<x->val){ Insert(x->l,y); if(x->l->p>x->p)Rotater(x); }else{ Insert(x->r,y); if(x->r->p>x->p)Rotatel(x); } } // 查找第k小的元素 int kth(node*x,int rnk){ while(x){ int d=x->l?x->l->size:0; if(rnk<=d)x=x->l; else if(rnk>d+x->cnt)rnk-=d+x->cnt,x=x->r; else return x->id; }return -1; } void Del_node(node*&u){pool[--top]=u;u=NULL;} // 将B树并入A树 void merge(node*&A,node*&B){ if(!B)return; if(B->l)merge(A,B->l); if(B->r)merge(A,B->r); Insert(A,*B); Del_node(B); }}int n,m,k,u,v,q; namespace Union_Find_Set{ int f[M],size[M],block; void Initialize(){ memset(f,0,sizeof(f)); block=n; } int Find(int x){ if(!f[x])f[x]=x,size[x]=1; if(f[x]==x)return x; return f[x]=Find(f[x]); } void Union(int x,int y){ x=Find(x); y=Find(y); if(x==y)return; if(size[x]>size[y])swap(x,y); f[x]=y; size[y]+=size[x]; block--; }}void Heuristic_merge(int x,int y){ int fx=Union_Find_Set::Find(x); int fy=Union_Find_Set::Find(y); if(fx==fy)return; if(Treap::root[fx]->size<Treap::root[fy]->size)swap(x,y),swap(fx,fy); Treap::merge(Treap::root[fx],Treap::root[fy]); Union_Find_Set::f[fy]=fx;}int main(){ using namespace Treap; Initialize(); Union_Find_Set::Initialize(); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&k); Union_Find_Set::f[i]=i; Insert(root[i],node(k,i)); } while(m--){ scanf("%d%d",&u,&v); Heuristic_merge(u,v); } scanf("%d",&q); char op[5]; while(q--){ scanf("%s",op); if(op[0]==‘B‘){ scanf("%d%d",&u,&v); Heuristic_merge(u,v); }else{ scanf("%d%d",&u,&v); printf("%d\n",kth(root[Union_Find_Set::Find(u)],v)); } }return 0;}
BZOJ 2733 [HNOI2012]永无乡(启发式合并+Treap+并查集)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。