bzoj2733: [HNOI2012]永无乡(splay+启发式合并/线段树合并)
Posted Sakits
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj2733: [HNOI2012]永无乡(splay+启发式合并/线段树合并)相关的知识,希望对你有一定的参考价值。
这题之前写过线段树合并,今天复习Splay的时候想起这题,打算写一次Splay+启发式合并。
好爽!!!
写了长长的代码(其实也不长),只凭着下午的一点记忆(没背板子。。。),调了好久好久,过了样例,submit,1A!
哇真的舒服
调试输出懒得删了QwQ
#include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<queue> #include<algorithm> #define ll long long #define which(x) (son[fq[x]][1]==x) using namespace std; const int maxn=500010,extar[2]={-2147483647,2147483647}; int n,m,x,y,z,tot,q,cnt; int fa[maxn],data[maxn],size[maxn],a[maxn],son[maxn][2],fq[maxn],id[maxn],root[maxn]; char ch[maxn]; void read(int &k) { int f=1;k=0;char c=getchar(); while(c<‘0‘||c>‘9‘)c==‘-‘&&(f=-1),c=getchar(); while(c<=‘9‘&&c>=‘0‘)k=k*10+c-‘0‘,c=getchar(); k*=f; } int gf(int x){return fa[x]==x?x:fa[x]=gf(fa[x]);} int search(int x,int k) { //printf("KPM%d %d %d\n",x,k,son[x][1]); if(data[x]<k&&son[x][1])return search(son[x][1],k); if(data[x]>k&&son[x][0])return search(son[x][0],k); return x; } void rotate(int x) { int f=fq[x];bool k=which(x); son[f][k]=son[x][!k]; son[x][!k]=f; son[fq[f]][which(f)]=x; fq[x]=fq[f]; fq[f]=x; if(son[f][k])fq[son[f][k]]=f; size[x]=size[f]; size[f]=size[son[f][0]]+size[son[f][1]]+1; //printf("%d %d %d ORZCZL\n",x,f,size[x]); } void splay(int x) { while(fq[x]) { int f=fq[x]; if(!fq[f]) { rotate(x); break; } if(which(x)^which(f))rotate(x); else rotate(f); rotate(x); } } void insert(int &x,int w) { //printf("%d %d\n",x,w); if(!x){x=++tot;data[tot]=a[w];size[tot]=1;id[x]=w;return;} int k=search(x,a[w]); //printf("qiguai%d %d %d\n",k,a[w],data[k]); //printf("QAQ"); ++tot; data[tot]=a[w];fq[tot]=k;id[tot]=w; if(a[w]<data[k])son[k][0]=tot; else son[k][1]=tot; size[tot]=1; while(k)size[k]++,k=fq[k]; splay(tot); x=tot; } int rank(int x,int k) { //++cnt; //printf("%d %d %d\n",x,k,size[son[x][0]]); //if(cnt>10)exit(0); if(size[son[x][0]]>=k)return rank(son[x][0],k); if((size[son[x][0]]+1)==k)return x; return rank(son[x][1],k-size[son[x][0]]-1); } void merge(int x,int y) { //printf("WUWUWU%d %d\n",x,y); if(son[x][0])merge(son[x][0],root[y]); insert(root[y],id[x]); if(son[x][1])merge(son[x][1],root[y]); } int main() { read(n);read(m); for(int i=1;i<=n;i++) { read(a[i]); fa[i]=i; } //for(int i=1;i<=n;i++)printf("OAO%d\n",gf(i)); for(int i=1;i<=m;i++) { read(x);read(y); fa[gf(x)]=gf(y); } //for(int i=1;i<=n;i++)printf("QAQ%d %d\n",gf(i),root[gf(i)]); //printf("\n"); for(int i=1;i<=n;i++)insert(root[gf(i)],i); //for(int i=1;i<=n;i++)printf("QAQ%d %d\n",gf(i),root[gf(i)]); //printf("%dQQQQQQQQQQQQQQ\n",son[root[gf(1)]][0]); read(q); for(int i=1;i<=q;i++) { scanf("%s",ch);read(x);read(y); if(ch[0]==‘Q‘) { x=gf(x); //printf("%d %d\n",root[x],size[root[x]]); if(size[root[x]]<y)printf("-1\n"); else { int pos=rank(root[x],y); printf("%d\n",id[pos]),splay(pos),root[x]=pos; } } else { x=gf(x);y=gf(y); if(x!=y) { //printf("%d %d %d %d\n",root[x],root[y],size[root[x]],size[root[y]]); if(size[root[x]]>size[root[y]])swap(x,y); fa[x]=y; merge(root[x],y); root[x]=0; } } } return 0; }
以上是关于bzoj2733: [HNOI2012]永无乡(splay+启发式合并/线段树合并)的主要内容,如果未能解决你的问题,请参考以下文章
[BZOJ] 2733: [HNOI2012]永无乡 #线段树合并+并查集