[平衡树+启发式合并] BZOJ2733: [HNOI2012]永无乡
来源:互联网 发布:mac 文稿占用空间 编辑:程序博客网 时间:2024/05/23 19:22
题意
永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示。某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛。如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a 和岛 b 是连 通的。现在有两种操作:B x y 表示在岛 x 与岛 y 之间修建一座新桥。Q x k 表示询问当前与岛 x连通的所有岛中第 k 重要的是哪座岛,即所有与岛 x 连通的岛中重要度排名第 k 小的岛是哪 座,请你输出那个岛的编号。
题解
数据结构练手水题。
注意到只有合并操作,很容易想到对于每个联通块建平衡树,然后不断启发式合并。
据说splay启发式合并是nlogn?
#include<cstdio>#include<algorithm>using namespace std;struct node{ int key,id,size; node* ch[2]; node(int x=0,int y=0,node* son=NULL){ key=x; id=y; size=1; ch[0]=ch[1]=son; } int cmp(int k){ if(key==k) return -1; return key<k?1:0; } void maintain(){ size=ch[0]->size+ch[1]->size+1; }} nil, *null=&nil;typedef node* P_node;void init_null(){ null->size=0; null->ch[0]=null->ch[1]=null; }void rot(P_node &p,int d){ P_node k=p->ch[d^1]; p->ch[d^1]=k->ch[d]; k->ch[d]=p; p->maintain(); k->maintain(); p=k;}void splay(P_node &p,int tkey){ int d1=p->cmp(tkey); if(d1!=-1){ P_node p2=p->ch[d1]; int d2=p2->cmp(tkey); if(d2!=-1){ splay(p2->ch[d2],tkey); if(d1==d2) rot(p,d1^1), rot(p,d2^1); else rot(p->ch[d1],d2^1), rot(p,d1^1); } else rot(p,d1^1); }}void Insert(P_node &p,int tkey,int id){ if(p==null) p=new node(tkey,id,null); else Insert(p->ch[p->key<tkey],tkey,id); p->maintain();}int Kth(P_node p,int k){ if(p->ch[0]->size==k-1) return p->id; if(p->ch[0]->size>=k) return Kth(p->ch[0],k); return Kth(p->ch[1],k-p->ch[0]->size-1);}const int maxn=100005;int fa[maxn],w[maxn],c[maxn];P_node rt[maxn];void Print(P_node p){ if(p==null) return; Print(p->ch[0]); c[++c[0]]=p->id; Print(p->ch[1]); delete p;}int getfa(int x){ return fa[x]==x?x:fa[x]=getfa(fa[x]); }void Merge(int x,int y){ if(getfa(x)==getfa(y)) return; P_node p1=rt[getfa(x)], p2=rt[getfa(y)]; if(p1->size<p2->size) swap(p1,p2); c[0]=0; Print(p2); for(int i=1;i<=c[0];i++) Insert(p1,w[c[i]],c[i]), splay(p1,w[c[i]]); x=getfa(x); y=getfa(y); rt[fa[x]=y]=p1;}int getint(){ char ch=getchar(); int res=0,ff=1; while(!('0'<=ch&&ch<='9')){ if(ch=='-') ff=-1; ch=getchar(); } while('0'<=ch&&ch<='9') res=res*10+ch-'0', ch=getchar(); return res*ff;}int n,m,Q;int main(){ freopen("bzoj2733.in","r",stdin); freopen("bzoj2733.out","w",stdout); init_null(); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) w[i]=getint(), fa[i]=i, rt[i]=new node(w[i],i,null); for(int i=1;i<=m;i++){ int x=getint(),y=getint(); Merge(x,y); } scanf("%d",&Q); while(Q--){ char ch=getchar(); while(ch!='B'&&ch!='Q') ch=getchar(); int x=getint(),y=getint(); if(ch=='B') Merge(x,y); else{ if(rt[getfa(x)]->size<y) printf("-1\n"); else{ int res=Kth(rt[getfa(x)],y); splay(rt[getfa(x)],w[res]); printf("%d\n",res); } } } return 0;}
0 0
- BZOJ2733 [HNOI2012]永无乡 平衡树启发式合并
- [BZOJ2733]HNOI2012永无乡|平衡树启发式合并
- [BZOJ2733][HNOI2012][启发式合并][平衡树]永无乡
- [平衡树+启发式合并] BZOJ2733: [HNOI2012]永无乡
- [BZOJ2733][HNOI2012]永无乡(平衡树+启发式合并)
- bzoj2733: [HNOI2012]永无乡 splay+启发式合并
- 【bzoj2733】【HNOI2012】【永无乡】【treap+启发式合并】
- 【BZOJ2733】[HNOI2012]永无乡【启发式合并】【Splay】
- BZOJ2733: [HNOI2012]永无乡 Splay启发式合并
- [BZOJ2733][HNOI2012]永无乡-Treap-启发式合并
- bzoj2733 [HNOI2012]永无乡(splay启发式合并)
- [BZOJ2733][HNOI2012]永无乡(并查集+splay启发式合并)
- BZOJ 2733 2733: [HNOI2012]永无乡 平衡树启发式合并
- BZOJ2733 永无乡 [启发式合并]
- BZOJ2733 永无乡 【splay启发式合并】
- [BZOJ2733][HNOI2012永无乡][线段树合并+并查集]
- [bzoj2733][HNOI2012]永无乡 线段树合并+并查集
- [HNOI2012]永无乡 SBT+启发式合并
- Android 多线程编程的总结
- 435. Non-overlapping Intervals
- 鸟哥的服务器《十二》ftp服务器
- eclipse junit测试
- crontab执行expdp命令无效
- [平衡树+启发式合并] BZOJ2733: [HNOI2012]永无乡
- 无监督学习(unsupervised learning) 4.自编码器
- Android必备技能之属性动画
- MySQL默认字段如何插入默认值
- [BZOJ4006][JLOI2015]管道连接(斯坦纳树+dp)
- vm安装centos7
- Oracle11.2.04透明网关链接SQL server
- requests模块学习
- 跟着Andrew Ng挑战Machine Learning(第二周):多元线性回归+特征缩放