平衡树三题:bzoj3224+bzoj3223+bzoj3196 普通平衡树 文艺平衡树 二逼平衡树(splay)
来源:互联网 发布:淘宝开放平台难吗 编辑:程序博客网 时间:2024/05/18 02:03
bzoj3224 Tyvj 1728 普通平衡树
原题地址:http://www.lydsy.com/JudgeOnline/problem.php?id=3224
题意:
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入x数
2. 删除x数(若有多个相同的数,因只删除一个)
3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
4. 查询排名为x的数
5. 求x的前驱(前驱定义为小于x,且最大的数)
6. 求x的后继(后继定义为大于x,且最小的数)
数据范围
1.n的数据范围:n<=100000
2.每个数的数据范围:[-2e9,2e9]
题解:
基础平衡树操作。
旧代码。
代码:
#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>using namespace std;const int N=100005;int n;int root=0;int fa[N],ch[N][2],size[N],cnt[N],key[N];int sz=0;inline void update(int k){ if(k) { size[k]=cnt[k]; if(ch[k][0]) size[k]+=size[ch[k][0]]; if(ch[k][1]) size[k]+=size[ch[k][1]]; } return;}inline bool get(int x){return ch[fa[x]][1]==x;}inline void rotate(int x,int &k){ int y=fa[x],z=fa[y]; int l,r; if(ch[y][0]==x) l=0;else l=1;r=l^1; if(y==k) k=x; else { if(ch[z][0]==y) ch[z][0]=x; else ch[z][1]=x; } ch[y][l]=ch[x][r]; fa[ch[x][r]]=y; ch[x][r]=y; fa[x]=z; fa[y]=x; update(y);update(x); return;}inline void splay(int x,int &k){ while(x!=k) { int y=fa[x],z=fa[y]; if(y!=k) { if(x==ch[y][0]^y==ch[z][0]) rotate(x,k); else rotate(y,k); } rotate(x,k); } return;}inline int findx(int x){ int now=root; while(1) { if(ch[now][0]&&x<=size[ch[now][0]]) now=ch[now][0]; else { int tmp=cnt[now]+(ch[now][0]?size[ch[now][0]]:0); if(x<=tmp) return key[now]; x-=tmp; now=ch[now][1]; } }}inline void insert(int x){ if(root==0) { sz++;size[sz]=1;ch[sz][0]=ch[sz][1]=0;root=sz;cnt[sz]=1;fa[sz]=0;key[sz]=x; return; } int now=root,f=0; while(1) { if(key[now]==x) {size[now]++;cnt[now]++;update(f);splay(now,root); break;} if(x<key[now]) { f=now;now=ch[now][0];} else{ f=now; now=ch[now][1];} if(now==0) { sz++;now=sz;size[sz]=1;cnt[sz]=1;ch[sz][0]=ch[sz][1]=0;fa[sz]=f;key[sz]=x; if(x<key[f]) ch[f][0]=sz; else ch[f][1]=sz; update(f); splay(now,root);break; } } return;}inline int find(int x){ int now=root,ans=0; while(1) { if(x<key[now]) now=ch[now][0]; else { ans+=(ch[now][0]?size[ch[now][0]]:0); if(key[now]==x){ splay(now,root); return ans+1;} ans+=cnt[now]; now=ch[now][1]; } }}inline void clear(int k){ ch[k][0]=ch[k][1]=key[k]=cnt[k]=size[k]=fa[k]=0;return;}inline int getpre(){ int now=ch[root][0]; while(ch[now][1]) now=ch[now][1]; return now;}inline int getnxt(){ int now=ch[root][1]; while(ch[now][0]) now=ch[now][0]; return now;}inline void de(int x){ int now=root,f=0; if(root==0) return; int sss=find(x); if(cnt[root]>1){cnt[root]--; update(root);return;} if(!ch[root][0]&&!ch[root][1]) {clear(root); root=0;return;} //注意改根清空。 if(!ch[root][0]) {int oldroot=root;root=ch[oldroot][1]; fa[root]=0; clear(oldroot);return;} if(!ch[root][1]) {int oldroot=root;root=ch[oldroot][0]; fa[root]=0; clear(oldroot);return;} else { int pre=getpre(); int oldroot=root; splay(pre,root); fa[ch[oldroot][1]]=root; ch[root][1]=ch[oldroot][1]; clear(oldroot);update(root); return; } }int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) { int a,b; scanf("%d%d",&a,&b); switch(a){ case 1: insert(b); break; case 2: de(b); break; case 3: printf("%d\n",find(b)); break; case 4: printf("%d\n",findx(b)); break; case 5: { insert(b); printf("%d\n",key[getpre()]); de(b); break; } case 6: { insert(b); printf("%d\n",key[getnxt()]); de(b); break; } } } return 0;}
bzoj3223 Tyvj 1729 文艺平衡树
原题地址:http://www.lydsy.com/JudgeOnline/problem.php?id=3223
题意:
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1
数据范围
N,M<=100000
题解:
基础splay操作。
旧代码。
代码:
#include<cstdio>#include<iostream>#include<cstring>using namespace std;const int N=100005;int fa[N],ch[N][2],id[N],size[N];int n,m,root;bool rev[N];void update(int k){ size[k]=size[ch[k][0]]+size[ch[k][1]]+1;}void build(int l,int r,int f){ if(l>r) return; int now=id[l];int last=id[f]; if(l==r) { size[now]=1;rev[now]=0;fa[now]=last; if(l<f) ch[last][0]=now; else ch[last][1]=now; return; } else { int mid=(l+r)>>1; now=id[mid]; build(l,mid-1,mid);build(mid+1,r,mid); rev[now]=0; fa[now]=last; if(mid<f) ch[last][0]=now; else ch[last][1]=now; update(now); }}void pushdown(int k){ if(rev[k]) { swap(ch[k][0],ch[k][1]); rev[ch[k][0]]^=1; rev[ch[k][1]]^=1; rev[k]=0; }}void rotate(int x,int &k){ int y=fa[x]; int z=fa[y]; int l,r; if(ch[y][0]==x) l=0; else l=1; r=l^1; if(y==k) k=x; else {if(ch[z][0]==y) ch[z][0]=x; else ch[z][1]=x;} fa[x]=z; fa[y]=x; fa[ch[x][r]]=y; ch[y][l]=ch[x][r];ch[x][r]=y; update(y);update(x);}void splay(int x,int &k) //传地址的意义 在于直接改变root { while(x!=k) { int y=fa[x],z=fa[y]; if(y!=k) { if(ch[y][0]==x^ch[z][0]==y) rotate(x,k); else rotate(y,k); } rotate(x,k); }}int find(int k,int rank){ pushdown(k); int l=ch[k][0];int r=ch[k][1]; if(size[l]+1==rank) return k; if(size[l]>=rank) return find(l,rank); else return find(r,rank-size[l]-1); }void rever(int l,int r){ int x=find(root,l);int y=find(root,r+2); splay(x,root); splay(y,ch[x][1]); int z=ch[y][0]; rev[z]^=1;}int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n+2;i++) id[i]=i; root=(n+3)>>1; build(1,n+2,0); int l,r; for(int i=1;i<=m;i++) { scanf("%d%d",&l,&r); rever(l,r); } for(int i=1;i<=n;i++) printf("%d ",find(root,i+1)-1); return 0;}
bzoj3196 Tyvj 1730 二逼平衡树
原题地址:http://www.lydsy.com/JudgeOnline/problem.php?id=3196
题意:
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
1.查询k在区间内的排名
2.查询区间内排名为k的值
3.修改某一位值上的数值
4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)
5.查询k在区间内的后继(后继定义为大于x,且最小的数)
数据范围
1.n和m的数据范围:n,m<=50000
2.序列中每个数的数据范围:[0,1e8]
3.虽然原题没有,但事实上5操作的k可能为负数
题解:
线段树套splay(大常数组合orz)
线段树的每一个节点建一个该区间的平衡树。(空间O(nlogn))
opt1:查询覆盖该区间的线段树节点对应平衡树中比k小的个数+1
opt2:二分这个数,转化为opt1
opt3:该点向上一条链的线段树平衡树中都删除一个这个点对应的值,插入一个这个点的新值。
opt4:查询覆盖该区间的线段树节点对应平衡树中该值前驱并取最大。
opt5:查询覆盖该区间的线段树节点对应平衡树中该值后并取最小。
(200行
代码:
#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>using namespace std;const int N=50005;const int NN=2000005;const int inf=0x3f3f3f3f;struct node{ int ch[2],fa,val,size,cnt; void init() { ch[0]=ch[1]=fa=val=size=cnt=0; }}tr[NN];struct NODE{ int ls,rs,root; void init() { ls=rs=root=0; }}TR[2*N];int n,m,tail=0,TAIL=0,a[N],root;void update(int nd){ int ls=tr[nd].ch[0]; int rs=tr[nd].ch[1]; tr[nd].size=tr[nd].cnt; if(ls) tr[nd].size+=tr[ls].size; if(rs) tr[nd].size+=tr[rs].size;}int insert(int &nd,int fa,int val){ if(!nd) {nd=++tail; tr[nd].init(); tr[nd].fa=fa; tr[nd].size=tr[nd].cnt=1; tr[nd].val=val; return nd;} int pos; if(val<tr[nd].val) pos=insert(tr[nd].ch[0],nd,val); else if(val>tr[nd].val) pos=insert(tr[nd].ch[1],nd,val); else {tr[nd].cnt++; pos=nd;} update(nd); return nd;}void rotate(int x,int &top){ int y=tr[x].fa; int z=tr[y].fa; if(y==top) top=x; else if(tr[z].ch[0]==y) tr[z].ch[0]=x; else tr[z].ch[1]=x; tr[x].fa=z; int l= (tr[y].ch[0]==x)? 0:1; int r=l^1; tr[y].ch[l]=tr[x].ch[r]; tr[tr[x].ch[r]].fa=y; tr[x].ch[r]=y; tr[y].fa=x; update(y); update(x);}void splay(int x,int &top){ while(x!=top) { int y=tr[x].fa; int z=tr[y].fa; if(y!=top) { if(tr[y].ch[0]==x ^ tr[z].ch[0]==y) rotate(x,top); else rotate(y,top); } rotate(x,top); }}void build(int &nd,int lf,int rg){ nd=++TAIL; for(int i=lf;i<=rg;i++) {int pos=insert(TR[nd].root,0,a[i]); splay(pos,TR[nd].root);} if(lf==rg) return; int mid=(lf+rg)>>1; build(TR[nd].ls,lf,mid); build(TR[nd].rs,mid+1,rg);}int query(int nd,int val){ if(!nd) return 0; if(tr[nd].val==val) return tr[tr[nd].ch[0]].size; else if(tr[nd].val<val) return tr[tr[nd].ch[0]].size+tr[nd].cnt+query(tr[nd].ch[1],val); else return query(tr[nd].ch[0],val);}int query(int nd,int lf,int rg,int L,int R,int val){ if(L<=lf&&rg<=R) return query(TR[nd].root,val); int ans=0; int mid=(lf+rg)>>1; if(L<=mid) ans+=query(TR[nd].ls,lf,mid,L,R,val); if(R>mid) ans+=query(TR[nd].rs,mid+1,rg,L,R,val); return ans;}int find(int nd,int val){ if(!nd) return 0; int ls=tr[nd].ch[0]; int rs=tr[nd].ch[1]; if(tr[nd].val==val) return nd; else if(val<tr[nd].val) return find(tr[nd].ch[0],val); else return find(tr[nd].ch[1],val);}int getpre(int x){ int tmp=tr[x].ch[0]; while(tr[tmp].ch[1]) tmp=tr[tmp].ch[1]; return tmp;}void del(int &x){ if(tr[x].cnt>1) {tr[x].cnt--; update(x); return;} if(!tr[x].ch[0]&&!tr[x].ch[1]) { tr[x].init(); x=0; return;} else if(!tr[x].ch[0]||!tr[x].ch[1]) { int l= tr[x].ch[0]==0? tr[x].ch[1]:tr[x].ch[0]; tr[x].init(); x=l; tr[x].fa=0; update(x); return; } int now=x; int pre=getpre(now); splay(pre,x); tr[pre].ch[1]=tr[now].ch[1]; tr[tr[now].ch[1]].fa=pre; tr[now].init(); update(pre); return;}void modify(int &nd,int pos,int val){ int pv=a[pos]; int x=find(nd,pv); splay(x,nd); del(nd); int now=insert(nd,n,val); splay(now,nd);}void modify(int nd,int lf,int rg,int pos,int val){ modify(TR[nd].root,pos,val); if(lf==rg) return; int mid=(lf+rg)>>1; if(pos<=mid) modify(TR[nd].ls,lf,mid,pos,val); if(pos>mid) modify(TR[nd].rs,mid+1,rg,pos,val);}int preval(int nd,int val){ int tmp=nd; int ans=-inf; while(tmp) { if(tr[tmp].val<val) { ans=max(tr[tmp].val,ans); tmp=tr[tmp].ch[1]; } else tmp=tr[tmp].ch[0]; } return ans;}int nxtval(int nd,int val){ int tmp=nd; int ans=inf; while(tmp) { if(tr[tmp].val>val) { ans=min(tr[tmp].val,ans); tmp=tr[tmp].ch[0]; } else tmp=tr[tmp].ch[1]; } return ans;}int query_pre(int nd,int lf,int rg,int L,int R,int val){ if(L<=lf&&rg<=R) return preval(TR[nd].root,val); int ans=-inf; int mid=(lf+rg)>>1; if(L<=mid) ans=max(ans,query_pre(TR[nd].ls,lf,mid,L,R,val)); if(R>mid) ans=max(ans,query_pre(TR[nd].rs,mid+1,rg,L,R,val)); return ans;}int query_nxt(int nd,int lf,int rg,int L,int R,int val){ if(L<=lf&&rg<=R) return nxtval(TR[nd].root,val); int ans=inf; int mid=(lf+rg)>>1; if(L<=mid) ans=min(ans,query_nxt(TR[nd].ls,lf,mid,L,R,val)); if(R>mid) ans=min(ans,query_nxt(TR[nd].rs,mid+1,rg,L,R,val)); return ans;}int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]); tr[0].init(); build(root,1,n); while(m--) { int opt,l,r,pos,k; scanf("%d",&opt); if(opt==1) //查询k在区间[l,r]内的排名 { scanf("%d%d%d",&l,&r,&k); printf("%d\n",query(root,1,n,l,r,k)+1); } else if(opt==2)//之后有三个数l,r,k 表示查询区间[l,r]内排名为k的数 { scanf("%d%d%d",&l,&r,&k); int lf=0; int rg=100000000; while(lf+1<rg) { int mid=(lf+rg)>>1; if(query(root,1,n,l,r,mid)+1<=k) lf=mid; else rg=mid; } if(query(root,1,n,l,r,rg)+1<=k) printf("%d\n",rg); else printf("%d\n",lf); } else if(opt==3)//之后有两个数pos,k 表示将pos位置的数修改为k { scanf("%d%d",&pos,&k); modify(root,1,n,pos,k); a[pos]=k; } else if(opt==4) { scanf("%d%d%d",&l,&r,&k); //之后有三个数l,r,k 表示查询区间[l,r]内k的前驱 printf("%d\n",query_pre(root,1,n,l,r,k)); } else if(opt==5) { scanf("%d%d%d",&l,&r,&k); //之后有三个数l,r,k 表示查询区间[l,r]内k的后驱 printf("%d\n",query_nxt(root,1,n,l,r,k)); } } return 0;}
- 平衡树三题:bzoj3224+bzoj3223+bzoj3196 普通平衡树 文艺平衡树 二逼平衡树(splay)
- BZOJ3196 3223 3224 二逼平衡树,文艺平衡树,普通平衡树
- [BZOJ3223] 文艺平衡树 - splay
- [BZOJ3223]文艺平衡树 splay
- bzoj3223文艺平衡树splay
- BZOJ3223&3224 文艺&普通平衡树 Splay模板(数组)
- BZOJ3223 文艺平衡树(Splay)
- [BZOJ3223]文艺平衡树(平衡树splay)
- [BZOJ3223]文艺平衡树(平衡树splay)
- bzoj3224普通平衡树 Splay
- [BZOJ3224] 普通平衡树 - splay
- BZOJ3224 普通平衡树(splay)
- [BZOJ3224][SPLAY]普通平衡树
- [BZOJ3224]普通平衡树 SPlay
- bzoj3224普通平衡树splay
- 【bzoj3223】文艺平衡树
- BZOJ3223文艺平衡树
- [bzoj3223]文艺平衡树
- 迭代法求平方根
- 11.25~11.26 python 学习笔记
- Agile Data Science 2.0.pdf 英文原版 免费下载
- 一千万日元:日本IT公司CAICA加入加密货币和ICO领域
- 射电肢体再生仪器建设构架【此文献给所有能看懂《源代码》电影的朋友】这不是换头手术成功,是再生成功。
- 平衡树三题:bzoj3224+bzoj3223+bzoj3196 普通平衡树 文艺平衡树 二逼平衡树(splay)
- linux web应用部署环境
- Apache Kafka.pdf 英文原版 免费下载
- 打开指定网站/系统文件夹
- Learning Apache Kafka, 2nd Edition.pdf 英文原版 免费下载
- 思科模拟器常用命令总结(续)
- 自己写的1046. 划拳(15)
- Apache Kafka Cookbook.pdf 英文原版 免费下载
- UART与USART区别