文艺平衡树 lg3391(splay维护区间入门)
Posted wenci
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了文艺平衡树 lg3391(splay维护区间入门)相关的知识,希望对你有一定的参考价值。
splay是支持区间操作的,先做这道题入个门
大多数操作都和普通splay一样,就不多解释了,只解释一下不大一样的操作
#include<bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f inline int read(){ int w=0,f=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘){ if(ch==‘-‘) f=-1; ch=getchar(); } while(ch>=‘0‘&&ch<=‘9‘){ w=(w<<3)+(w<<1)+ch-48; ch=getchar(); } return w*f; } int n,m,tot,cnt,root; struct node{ int ch[2],sum,cnt,val,f,rev;//比普通平衡树多一个lazy tag }st[1000010]; inline void push_up(int p){ st[p].sum=st[st[p].ch[0]].sum+st[st[p].ch[1]].sum+st[p].cnt; } inline bool identify(int p){ return st[st[p].f].ch[1]==p; } inline void connect(int x,int fa,int son){ st[x].f=fa;st[fa].ch[son]=x;return; } inline void rotate(int x){ int y=st[x].f;int z=st[y].f; int yson=identify(x);int zson=identify(y); int b=st[x].ch[yson^1]; connect(b,y,yson);connect(y,x,(yson^1));connect(x,z,zson); push_up(y);push_up(x);return; } inline void splay(int x,int goal){ while(st[x].f!=goal){ int y=st[x].f;int z=st[y].f; int yson=identify(x);int zson=identify(y); if(z!=goal){ if(yson==zson) rotate(y); else rotate(x); } rotate(x); } if(!goal) root=x; return; } inline void insert(int x){ int now=root;int f=0; while(st[now].val!=x&&now){ f=now; now=st[now].ch[x>st[now].val]; } if(now){ st[now].cnt++; } else{ tot++;now=tot; if(f){ st[f].ch[x>st[f].val]=now; } st[now].ch[0]=st[now].ch[1]=0; st[now].cnt=st[now].sum=1; st[now].val=x;st[now].f=f; } splay(now,0);return; } inline void push_down(int p){ int ls=st[p].ch[0];int rs=st[p].ch[1]; if(st[p].rev){ swap(st[p].ch[0],st[p].ch[1]); st[st[p].ch[0]].rev^=1; st[st[p].ch[1]].rev^=1; st[p].rev=0; } } inline void find(int x){ int now=root;if(!now) return; while(st[now].val!=x&&st[now].ch[x>st[now].val]){ now=st[now].ch[x>st[now].val]; } splay(now,0);return; } inline int Next(int x,int f){ find(x);int now=root; if(st[now].val<x&&!x) return now; if(st[now].val>x&&x) return now; now=st[now].ch[f]; while(st[now].ch[f^1]) now=st[now].ch[f^1]; return now; } inline int k_th(int x){ int now=root; if(st[now].sum<x) return false; while(true){ push_down(now);//在查找的时候记得下移标记 int ls=st[now].ch[0]; if(x>st[ls].sum+st[now].cnt){ x-=st[ls].sum+st[now].cnt; now=st[now].ch[1]; } else if(x<=st[ls].sum){ now=ls; } else return now;//这个地方把返回原值改成返回位置 } }inline void rev(int l,int r){ int x=k_th(l-1);int y=k_th(r+1); splay(x,0);splay(y,x); st[st[y].ch[0]].rev^=1; }//翻转的操作就是将l-1转到根上,r+1转到根的右儿子,然后l到r这个区间就是根右儿子的左儿子(比较绕,可以画个图想一想 inline void output(int p){ push_down(p); if(st[p].ch[0]) output(st[p].ch[0]); if(st[p].val>=1&&st[p].val<=n) printf("%d ",st[p].val); if(st[p].ch[1]) output(st[p].ch[1]); }//输出的时候下推一下标记,输出顺序就是二叉树的顺序 int main(){ n=read();m=read();int i,j,k; insert(INF);insert(-INF); for(i=1;i<=n;i++){ insert(i); } while(m--){ int x,y;x=read();y=read(); rev(x+1,y+1); } output(root); return 0; }
以上是关于文艺平衡树 lg3391(splay维护区间入门)的主要内容,如果未能解决你的问题,请参考以下文章