【模板】Splay

lindongli2004

2019-02-19 15:56:41

Personal

## **Splay** 是平衡树的一种,拥有强大的功能。 1. ### 功能简介 主要表现:维护数列 - 插入元素 - 删除元素 - 区间修改(例如区间加,区间赋值等) - 区间询问(例如区间最大值,区间和) - 区间翻转 2. ### 我的理解 - 是一颗相对平衡的二叉搜索树 - 维护相对平衡的关键是双旋 ( splay ) - 可以像线段树一样灵活地维护(下放)标记 - 而平衡树优秀的时空复杂度和灵活程度,决定了其强大的功能 3. ### 被坑的地方 - 定义了全局变量 x ,又定义的一个局部变量 x 。 - 没有提前插入两个虚拟结点 。 - 注意 **rotate** 函数的细节问题。 4. ### 复杂度 $$O(n logn)$$ 下面贴 **splay** 的模板题:**NOI2005维护数列** pre:找到区间[l,r]的方法:splay(x,root),splay(y,x). 其中, x=find(l-1), y=find(r+1), find(a)表示 a 在 splay 中的编号。 这样 y 的左子树就对应区间[l,r]. 1.对于插入操作, 我们可以利用 build() 函数, 类似线段树的建树, 再进行插入. 2.对于删除操作, 找到对应的区间, 再进行删除. 3.对于修改操作, 找到对应的区间, 打上修改标记. 4.对于翻转操作, 找到对应的区间, 打上翻转标记. 5.对于求和操作, 找到对应的区间, 返回改结点的子树和. 6.对于最大子段和, 直接 O(1) 输出 root 的最大子段和权值. 7.下传标记优先级: 赋值 > 翻转及其他. 8. updata() 同线段树维护最大子段和相同. code: ```cpp #include<iostream> #include<cstdio> using namespace std; const int N=1002018,INF=1e9+7; int n, q, top, cnt, rt; bool rev[N], tag[N]; char s[12]; int stk[N], fa[N], c[N][2], v[N], a[N], mx[N], lmx[N], rmx[N], sum[N], siz[N], id[N]; void updata(int x){ int l=c[x][0],r=c[x][1]; siz[x]=siz[l]+siz[r]+1; sum[x]=sum[l]+sum[r]+v[x]; mx[x]=max(rmx[l]+v[x]+lmx[r], max(mx[l], mx[r])); lmx[x]=max(lmx[l], sum[l]+v[x]+lmx[r]); rmx[x]=max(rmx[r], sum[r]+v[x]+rmx[l]); } void down(int x){ int l=c[x][0], r=c[x][1]; if(tag[x]){ rev[x]=tag[x]=0; if(l)tag[l]=1, sum[l]=siz[l]*(v[l]=v[x]); if(r)tag[r]=1, sum[r]=siz[r]*(v[r]=v[x]); if(v[x] >= 0){ if(l)mx[l]=lmx[l]=rmx[l]=sum[l]; if(r)mx[r]=lmx[r]=rmx[r]=sum[r]; } else{ if(l)mx[l]=v[x], lmx[l]=rmx[l]=0; if(r)mx[r]=v[x], lmx[r]=rmx[r]=0; } } if(rev[x]){ rev[x]=0; rev[l]^=1; rev[r]^=1; swap(lmx[l],rmx[l]); swap(lmx[r],rmx[r]); swap(c[l][0], c[l][1]); swap(c[r][0], c[r][1]); } } int find(int x, int kth){ down(x);//cout<<"!!!!!"<<endl; int l=c[x][0], r=c[x][1]; if(siz[l]+1==kth)return x; if(siz[l]>=kth)return find(l, kth); else return find(r, kth-siz[l]-1); } inline bool get(int x){ return c[fa[x]][1]==x; } void rotate(int x, int &k){ int y=fa[x], z=fa[y], w=get(x); if(y==k)k=x;else c[z][c[z][1]==y]=x; c[y][w]=c[x][w^1]; fa[c[y][w]]=y; c[x][w^1]=y; fa[y]=x; fa[x]=z; updata(y); updata(x); } void splay(int x, int &k){ while(x != k){ int y=fa[x], z=fa[y]; if(y != k) rotate((get(x)^get(y))?x:y, k); rotate(x, k); } } void build(int l, int r, int f){ int mid=(l+r)>>1, now=id[mid], pre=id[f]; if(l==r){ lmx[now]=rmx[now]=max(0, a[l]); mx[now]=sum[now]=a[l]; tag[now]=rev[now]=0; siz[now]=1; } if(l<mid)build(l, mid-1, mid); if(mid<r)build(mid+1, r, mid); v[now]=a[mid]; fa[now]=pre; updata(now); c[pre][mid>=f]=now; } int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void INSERT(int k, int tot){ for(int i=1;i<=tot;i++)a[i]=read(); for(int i=1;i<=tot;i++){ if(top>0)id[i]=stk[top--]; else id[i]=++cnt; } build(1,tot,0); int z=id[(1+tot)>>1], x=find(rt, k+1), y=find(rt, k+2); splay(x, rt); splay(y, c[x][1]); fa[z]=y; c[y][0]=z; updata(y); updata(x); } int split(int k, int tot){ int x=find(rt, k), y=find(rt, k+tot+1); splay(x, rt); splay(y, c[x][1]); return c[y][0]; } void recycle(int x){ int &l=c[x][0], &r=c[x][1]; if(l)recycle(l); if(r)recycle(r); stk[++top]=x; fa[x]=l=r=tag[x]=rev[x]=0; } void DELETE(int k, int tot){ int x=split(k, tot), y=fa[x]; recycle(x); c[y][0]=0; updata(y); updata(fa[y]); } void MODIFY(int k, int tot, int val){ int x=split(k, tot), y=fa[x]; tag[x] = 1;v[x]=val; sum[x]=siz[x]*val; if(val >= 0)lmx[x]=rmx[x]=mx[x]=sum[x]; else lmx[x]=rmx[x]=0, mx[x]=val; updata(y); updata(fa[y]); } void RAVER(int k, int tot){ int x=split(k, tot), y=fa[x]; if(!tag[x]){ rev[x]^=1; swap(c[x][0], c[x][1]); swap(lmx[x], rmx[x]); updata(y); updata(fa[y]); } } int QUERY(int k,int tot){ int x=split(k, tot); return sum[x]; } void dfs(int x){ down(x); if(c[x][0])dfs(c[x][0]); if(c[x][1])dfs(c[x][1]); } int main() { n=read();q=read(); for(int i=1;i<=n;i++)a[i+1]=read(); mx[0]=a[1]=a[n+2]=-INF; for(int i=1;i<=n+2;i++)id[i]=i; build(1,n+2,0); rt=(n+3)>>1;cnt=n+2; while(q--){ scanf("%s", s); if(s[0]=='M' && s[2]=='X'){printf("%d\n", mx[rt]);continue;} int x=read(),tot=read(); if(s[0] == 'I')INSERT(x, tot); if(s[0] == 'D')DELETE(x, tot); if(s[0] == 'M'){ int val=read(); MODIFY(x, tot, val); } if(s[0] == 'R')RAVER(x, tot); if(s[0] == 'G')printf("%d\n", QUERY(x, tot)); } return 0; } ``` **ps:留坑慢慢补**