splay反转-P3391 文艺平衡树
来源:互联网 发布:linux下重启的命令 编辑:程序博客网 时间:2024/05/29 17:20
https://daniu.luogu.org/problem/show?pid=3391
首先你要理解splay的旋转;
其实反转和treap是一样的,都是二叉树的旋转;
但是treap用随机数来维护树高,而slplay用双旋来维护;
那我们怎么翻转这个区间呢?
对于l~r
我们先把l-1旋转到根节点
再把r+1旋转到更节点的右儿子;
显然,这样树根的右子节的左子节点点是l~r;
那么我们只要把这个区间打一个标记;
一旦我们要访问这个节点,先交换左右子树,再把标记下穿;
如果子树已经有标记就抵消;
这样就实现了翻转区间;
然后我们为l-1,r+1不越界,所以我们把整个区间的范围变化成0~n+2;
这样的话要注意一些细节问题;
有些心得说说;
在这个树里,树的权值(即节点)是一开始的下标;
但是我们维护的时这些下标的顺序;
因为顺序的变化,所以我们要把节点与节点之间的关系换掉;
但是节点本身不变;
这个就是和以前学的线段树什么的不一样的地方;
所以我们在写这类二叉搜索树的时候,一定要搞清楚。
我们维护的顺序是什么,节点的权值是什么;
#include<iostream>#include<cstdio>#include<cstring>using namespace std;int c[100005][2],fa[100005],size[100005],rev[100005];//c数组记录左右儿子,rev就是标记; int n,m,x,y,z,rt;void pushup(int x){size[x]=size[c[x][0]]+size[c[x][1]]+1;}void pushdown(int x){ if(!rev[x])return; swap(c[x][0],c[x][1]); rev[c[x][0]]^=1; rev[c[x][1]]^=1; rev[x]=0;}void make(int l,int r,int z){ if(l>r)return; if(l==r){ fa[l]=z; size[l]=1; if(l<z)c[z][0]=l;else c[z][1]=l; return; } int mid=l+r>>1; make(l,mid-1,mid); make(mid+1,r,mid); fa[mid]=z; pushup(mid); if(mid<z)c[z][0]=mid;else c[z][1]=mid;}int find(int x,int k){ pushdown(x); if(size[c[x][0]]+1==k)return x; if(size[c[x][0]]+1>k)return find(c[x][0],k); return find(c[x][1],k-size[c[x][0]]-1);}void turn(int x,int &k){ int y=fa[x],z=fa[y],l,r; if(c[y][0]==x)l=0;else l=1; r=l^1;//这里直接用l,r表示节点,这就是c[][0/1]的妙用,思想类似与滚存; if(y==k)k=x;else if(c[z][0]==y)c[z][0]=x;else c[z][1]=x; fa[x]=z;fa[y]=x;fa[c[x][r]]=y; c[y][l]=c[x][r]; c[x][r]=y; pushup(y); pushup(x);}void splay(int x,int &k){ while(x!=k){//为什么这里x不用变,因为我们把x和其他点的关系改掉了,本身的x是不用边的; //但是k最终会变成x; int y=fa[x],z=fa[y]; if(y!=k)//如果y不是k,直接转两次,不然转一次; if(c[y][0]==x^c[z][0]==y)turn(x,k); else turn(y,k); turn(x,k); }}void rever(int l,int r){ int x=find(rt,l),y=find(rt,r); splay(x,rt); splay(y,c[rt][1]); rev[c[y][0]]^=1;//用异或去添加,抵消标记 }int main(){ scanf("%d%d",&n,&m); make(1,n+2,0);rt=(n+3)>>1;//建造一个0~n+2的树,节点个数是n+3个; while(m--){ scanf("%d%d",&x,&y); x++;y++; rever(x-1,y+1); } for(int i=2;i<=n+1;i++)printf("%d ",find(rt,i)-1); //因为我们一开始建立的0~n+2的区间,用了n+3个位子,第一个位子的下标是1,但是我们第一个数是0而不是1,所以-1; }
2 4
- splay反转-P3391 文艺平衡树
- P3391 【模板】文艺平衡树(Splay)
- 洛谷 P3391 文艺平衡树
- 洛谷 P3391 文艺平衡树
- 【BZOJ3223】文艺平衡树,Splay反转区间
- luogu解题报告:P3391文艺平衡树
- [BZOJ3223] 文艺平衡树 - splay
- [BZOJ3223]文艺平衡树 splay
- bzoj3223文艺平衡树splay
- BZOJ3223: Tyvj 1729 文艺平衡树(洛谷P3391)
- 【splay】splay小结 文艺平衡树
- 【bzoj3223】文艺平衡树【Splay】【呵呵】
- BZOJ 3223 文艺平衡树 (splay)
- BZOJ3223 文艺平衡树(Splay)
- 【Splay】bzoj 3223 文艺平衡树
- BZOJ 3223 文艺平衡树 【Splay】
- 【bzoj3223】Tyvj 1729 文艺平衡树 Splay
- 【splay】BZOJ 3223 文艺平衡树
- SpringMVC常用标签及其功能
- 基于阻塞队列实现消费者和生产者
- 推荐一个好用的网站icon处理网站
- 安装 PL/SQL后,对tnsnames.ora的配置
- 单元测试-JMockit中使用参数化(多参数)测试
- splay反转-P3391 文艺平衡树
- Redis与Memcache
- .net core npoi 将excal 导入数据库
- 关于tomcat无法访问8080页面 报404的错误
- Charles 抓包工具的Mac下使用
- MySQL事务个人理解
- YOJ2379:反恐精英
- 传奇3的WIL文件格式
- 地区多级列表实现