【BZOJ2733】永无乡(HNOI2012)-平衡树启发式合并
2018-03-11 18:15
357 查看
测试地址:永无乡
做法:本题需要用到平衡树启发式合并。
题目要维护每个连通块的第kk大,并且要支持合并。维护第kk大我们知道可以用平衡树解决,但是平衡树的合并我们好像除了暴力就没有想法了。怎么样比较快地合并两棵平衡树?想法上非常简单,我们只需要暴力把点数比较小的那棵平衡树上的点一一插入到另一棵平衡树上。为什么这样就更优了呢?因为每次合并,新平衡树的大小必然是原小平衡树的两倍以上,那么每个元素就最多会被插入lognlogn次,所以总的复杂度就是O(nlog2n)O(nlog2n)的,可以承受。
好像根据某个定理,按小平衡树的中序遍历插入好像能达到O(nlogn)O(nlogn)……虽然好像感觉没有变快,但应该还是能优化些常数的。
以下是本人代码:
做法:本题需要用到平衡树启发式合并。
题目要维护每个连通块的第kk大,并且要支持合并。维护第kk大我们知道可以用平衡树解决,但是平衡树的合并我们好像除了暴力就没有想法了。怎么样比较快地合并两棵平衡树?想法上非常简单,我们只需要暴力把点数比较小的那棵平衡树上的点一一插入到另一棵平衡树上。为什么这样就更优了呢?因为每次合并,新平衡树的大小必然是原小平衡树的两倍以上,那么每个元素就最多会被插入lognlogn次,所以总的复杂度就是O(nlog2n)O(nlog2n)的,可以承受。
好像根据某个定理,按小平衡树的中序遍历插入好像能达到O(nlogn)O(nlogn)……虽然好像感觉没有变快,但应该还是能优化些常数的。
以下是本人代码:
#include <bits/stdc++.h> using namespace std; int n,m,q; int top[100010],fa[100010],ch[100010][2],key[100010],siz[100010]; void pushup(int x) { siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1; } void rotate(int x,bool f) { int y=fa[x]; ch[y][!f]=ch[x][f]; fa[ch[x][f]]=y; if (fa[y]) ch[fa[y]][ch[fa[y]][1]==y]=x; fa[x]=fa[y]; fa[y]=x; ch[x][f]=y; pushup(y),pushup(x); } void Splay(int x,int &rt,int goal) { while(fa[x]!=goal) { if (fa[fa[x]]==goal) rotate(x,ch[fa[x]][0]==x); else { int y=fa[x],z=fa[fa[x]]; bool f=(ch[y][1]==x); if (ch[z][f]==y) rotate(y,!f),rotate(x,!f); else rotate(x,!f),rotate(x,f); } } if (goal==0) rt=x; } int find_kth(int x,int k) { int rt; Splay(x,rt,0); if (siz[x]<k) return -1; while(siz[ch[x][0]]+1!=k) { int s=siz[ch[x][0]]+1; if (k<s) x=ch[x][0]; else x=ch[x][1],k-=s; } Splay(x,rt,0); return x; } void insert(int &v,int &rt,int x,int f) { if (!v) { v=x; ch[v][0]=ch[v][1]=0; fa[v]=f; Splay(v,rt,0); return; } insert(ch[v][key[x]>key[v]],rt,x,v); } int find(int x) { int r=x,i=x,j; while(r!=top[r]) r=top[r]; while(i!=r) {j=top[i],top[i]=r,i=j;} return r; } void order(int v,int &rty) { if (ch[v][0]) order(ch[v][0],rty); if (ch[v][1]) order(ch[v][1],rty); insert(rty,rty,v,0); } void merge(int x,int y) { int fx=find(x),fy=find(y),rt; top[fy]=fx; Splay(x,rt,0),Splay(y,rt,0); if (siz[x]>siz[y]) swap(x,y); order(x,y); } int main() { scanf("%d%d",&n,&m); siz[0]=0; for(int i=1;i<=n;i++) { top[i]=i; fa[i]=ch[i][0]=ch[i][1]=0; siz[i]=1; scanf("%d",&key[i]); } for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); if (find(x)!=find(y)) merge(x,y); } scanf("%d",&q); while(q--) { char op[5]; int x,y; scanf("%s%d%d",op,&x,&y); if (op[0]=='B'&&find(x)!=find(y)) merge(x,y); if (op[0]=='Q') printf("%d\n",find_kth(x,y)); } return 0; }
相关文章推荐
- BZOJ2733 [HNOI2012]永无乡 平衡树启发式合并
- 【pb_ds】【平衡树启发式合并】【并查集】bzoj2733 [HNOI2012]永无乡
- [平衡树+启发式合并] BZOJ2733: [HNOI2012]永无乡
- [BZOJ2733][HNOI2012][启发式合并][平衡树]永无乡
- [BZOJ2733][HNOI2012]永无乡(平衡树+启发式合并)
- bzoj2733: [HNOI2012]永无乡 splay+启发式合并
- ☆ [HNOI2012] 永无乡 「平衡树启发式合并」
- BZOJ2733: [HNOI2012]永无乡 Splay启发式合并
- [BZOJ2733][HNOI2012]永无乡(并查集+splay启发式合并)
- bzoj2733: [HNOI2012]永无乡 启发式合并
- 【BZOJ2733】【HNOI2012】永无乡(Splay启发式合并)
- bzoj2733 [HNOI2012]永无乡(splay启发式合并)
- 【BZOJ2733】[HNOI2012]永无乡【启发式合并】【Splay】
- BZOJ 2733 HNOI 2012 永无乡 平衡树启发式合并
- 【bzoj2733】[HNOI2012]永无乡 Treap启发式合并
- 【BZOJ2733】永无乡[HNOI2012](splay启发式合并or线段树合并)
- bzoj 2733: [HNOI2012]永无乡(线段树启发式合并)
- 【bzoj2733】【HNOI2012】【永无乡】【treap+启发式合并】
- BZOJ 2733: [HNOI2012]永无乡 [splay启发式合并]
- BZOJ 2733 [HNOI2012] 永无乡 [splay+启发式合并做法]