[UVA11922]Permutation Transformer(splay树的序列分裂旋转应用)
2015-11-22 11:22
459 查看
splay_tree第一题,总算开始做白书了。。。
参考白书程序写(chao)了写(chao),意外的很快就ac了
ACCODE和注释奉上:
参考白书程序写(chao)了写(chao),意外的很快就ac了
ACCODE和注释奉上:
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> using namespace std; int n,m; struct Poi{ Poi *s[2]; int v,siz,flag; Poi(){}//新建节点:null专用 Poi(int v,Poi* nl):v(v){//新建节点:带值 s[0]=s[1]=nl;siz=v+1;flag=0; } int cmp(int x){//判断旋转方向 if (x==s[0]->siz+1) return -1; return x<s[0]->siz+1?0:1; } void maintain(){//调整size siz=s[0]->siz+s[1]->siz+1; } void push_down(){//lazy翻转标记下传 if (!flag) return; flag=0; swap(s[0],s[1]);//翻转 s[0]->flag^=1;s[1]->flag^=1;//标记下传 } }; struct Splay_tree{ Poi *root; Poi *null; void build(Poi* &ro,int kk){//建树 if (kk<0) return; ro=new Poi(kk,null);//新建带值节点 build(ro->s[0],kk-1); //递归:保证root节点被更新 ,注意ro是传地址的 } void init(int n){ null=new Poi;//null节点 null->s[0]=null->s[1]=null; null->v=null->siz=null->flag=0; root=null; build(root,n);//建树 } void rotate(Poi *&ro,int d){ Poi *tmp=ro->s[d^1];//要旋转上来的节点 ro->s[d^1]=tmp->s[d]; tmp->s[d]=ro; //旋转 ro->maintain();tmp->maintain(); ro=tmp;//返回已旋转上来的节点 } void splay_kth(Poi *&ro,int k){//将第k个节点调整到ro的位置 ro->push_down();//先下传标记 int d1=ro->cmp(k);//获得旋转方向 if (d1==1) k-=ro->s[0]->siz+1; if (d1!=-1){ Poi *p=ro->s[d1]; p->push_down(); int d2=p->cmp(k); if (d2!=-1){ int k2=d2==0?k:k-p->s[0]->siz-1; splay_kth(p->s[d2],k2);//先旋转下一层 if (d1==d2) rotate(ro,d1^1);//这里是双旋!! else rotate(ro->s[d1],d1); } rotate(ro,d1^1); //双旋 } } void split(Poi *ro,int k,Poi *&le,Poi *&ri){ splay_kth(ro,k);//将第k个节点移到ro处 le=ro;ri=ro->s[1];//分裂 ro->s[1]=null;//断开连接 le->maintain(); } Poi *merge(Poi *le,Poi *ri){ splay_kth(le,le->siz);//将左序列的最末旋转到根的位置 le->s[1]=ri;//连接 le->maintain(); return le;//返回现在的根节点 } void solve(int x,int y){ Poi *le,*ri,*mid,*tmp;//分裂序列,“0”~x,x+1~y,y~n split(root,x,le,tmp);//考虑最前面的虚拟节点“0”,长度需要加1变为x; split(tmp,y-x+1,mid,ri);//这里tmp是分裂出来的一棵树的根节点 mid->flag^=1;//翻转的lazy标记 root=merge(merge(le,ri),mid);//合并操作 } void print(Poi *&ro){//先序遍历输出 if (ro==null) return; ro->push_down();//输出前下传标记 print(ro->s[0]);//先输出左边 if (ro->v) printf("%d\n",ro->v);//如果不是虚拟节点就输出 print(ro->s[1]);//再输出右边 } }tr; int main(){ scanf("%d%d",&n,&m); tr.init(n);//初始化建树 int x,y; for (int i=1;i<=m;i++){ scanf("%d%d",&x,&y); tr.solve(x,y); } tr.print(tr.root); }
相关文章推荐
- 正常编写的程序出现androidmainfest.xml missing错误怎么做
- [LeetCode] Range Sum Query - Mutable 区域和检索 - 可变
- Operating System: Three Easy Pieces --- Locks (Note)
- LEETCODE-Kth Smallest Element in a BST
- HDU 5568 sequence2(大数+DP)
- .NET实现Repeater控件+AspNetPager控件分页
- Linux查看CPU个数
- centos6.5安装apache2.x并修改默认80端口
- Python 快速教程(Django07):马不停蹄
- 图——应用图的深度优先遍历思路求解问题
- Python 快速教程(Django06):假作真时
- sudo: ulimit: command not found
- 01 docker 安装操作
- IOS基础动画使用1
- 类模板的定义和使用
- Bootstrap 网格系统(Grid System)实例5
- NFS FTP Samba 搭建
- Bootstrap 网格系统(Grid System)实例4
- 四位一体数码管总有一位比其它数码管明显变亮
- zzulioj 1784: Camellia的难题 (暴力) 好坑