Splay专题
来源:互联网 发布:php视频解析源码 编辑:程序博客网 时间:2024/06/05 11:10
建树
void build(int l,int r,int &id,int f){ if(l>r)return; int mid=(l+r)>>1; New(id,f,A[mid]); build(l,mid-1,ch[id][0],id); build(mid+1,r,ch[id][1],id); up(id); }void init(int n){ ch[0][0]=ch[0][1]=sz[0]=par[0]=val[0]=0;//初始化空地址 sum[0]=dly[0]=0; root=0;num=0; New(root,0,0);//先把0插入到树中 New(ch[root][1],root,0);//在把n+1插入到树中 for(int i=1;i<=n;i++)scanf("%d",&A[i]); build(1,n,ch[ch[root][1]][0],ch[root][1]);//建成一棵比较平衡的二叉树放进去 up(ch[root][1]); up(root); }
基本模板
void New(int &id,int f,int v){ id=++num; val[id]=v; ch[id][0]=ch[id][1]=0; par[id]=f; sum[id]=dly[id]=0; sz[id]=1;}void rotate(int x){ //rotate部分不需要down了,找到x时,rotateTo函数已经把x所有的父亲都down了 int y=par[x]; int d=ch[y][0]==x;//d=1右旋,d=0左旋 //3根线发生变化 ch[y][!d]=ch[x][d]; if(ch[x][d])par[ch[x][d]]=y;//第一根线 par[x]=par[y];//第二根 if(par[y])ch[par[y]][ch[par[y]][1]==y]=x; ch[x][d]=y;par[y]=x;//第三根 up(y); //x不需要up,因为x还要继续往上旋 } void Splay(int x,int goal){ //当x的父亲和爷爷不在一个方向时,旋两次x //否则,先旋父亲,再旋x while(par[x]!=goal){ int y=par[x]; if(par[y]==goal)rotate(x); else{ int z=par[y]; if(ch[z][0]==y^ch[y][0]==x)rotate(x); else rotate(y); rotate(x); } } up(x); if(goal==0)root=x; }void rotateTo(int k,int goal){ //因为0也占了一个位置,所以第k个数,就变成左边有x个数的位置。 int p=root; down(p);//因为可能有翻转操作,左右儿子先需要交换,每次都先down一下 while(sz[ch[p][0]]!=k){ if(sz[ch[p][0]]>k){//在左儿子中 p=ch[p][0]; }else{//在右儿子中 k-=sz[ch[p][0]]+1; p=ch[p][1]; } down(p); } Splay(p,goal);//p就是第k个数所在的内存地址 }
功能
<1>查找前驱后继
int lower(int x){int cur=root,mi=1e9; while(cur){ if(val[cur]==x)return 0; if(val[cur]<x){ mi=min(mi,x-val[cur]); cur=ch[cur][1]; }else cur=ch[cur][0]; }return mi;}int upper(int x){ int cur=root,mi=1e9; while(cur){ if(val[cur]==x)return 0; if(val[cur]>x){ mi=min(mi,val[cur]-x); cur=ch[cur][0]; }else cur=ch[cur][1]; }return mi;}
<2>
删除节点
void delt(){ //更新因为删除该节点所改变的信息 int pre=get_pre(); int nxt=get_nxt(); int rot=root; if(pre==-1)root=ch[root][1]; else if(nxt==-1)root=ch[root][0]; if(~pre&&~nxt){ Splay(pre,root); par[pre]=nxt;//把前驱接在后继上 ch[nxt][0]=pre; root=ch[root][1];//以原来的右儿子为根 }par[root]=0;}
<3>
查找low和upper 类似于二分;如果找low。
我们对于val < x 的节点更新答案然后到它的右节点上(使val变大)
反之则到左节点上
int lower(int x){ int cur=root,ans=-1e9; while(cur){ if(val[cur]<=x){ ans=max(ans,val[cur]); cur=ch[cur][1]; }else cur=ch[cur][0]; }return ans;}int upper(int x){ int cur=root,ans=1e9; while(cur){ if(val[cur]>=x){ ans=min(ans,val[cur]); cur=ch[cur][0]; }else cur=ch[cur][1]; }return ans;}
<4>区间查询和更新
如图我们只需把l-1旋到根在把r+1旋上去那么r+1的左子树即为我们要的区间
void update(int l,int r,int v){ rotateTo(l-1,0);//以l-1为root rotateTo(r+1,root);//以r+1为ch[root][1] int need=ch[ch[root][1]][0];//need就为[l,r] dly[need]+=v;//delay延迟更新 val[need]+=v; sum[need]+=1ll*v*sz[need];}ll query(int l,int r){ rotateTo(l-1,0); rotateTo(r+1,root); return sum[ch[ch[root][1]][0]];}
<5> 翻转和覆盖
利用down 来延迟更新
void down_c(int p,int c){ cov[p]=1;val[p]=c; sum[p]=sz[p]*c; mx[p]=lsum[p]=rsum[p]=max(c,sum[p]); } void down_r(int p){ rev[p]^=1; swap(ch[p][0],ch[p][1]); swap(lsum[p],rsum[p]); } void down(int p){ int l=ch[p][0],r=ch[p][1]; if(rev[p]){ if(l)down_r(l); if(r)down_r(r); rev[p]=0; } if(cov[p]){ if(l)down_c(l,val[p]); if(r)down_c(r,val[p]); cov[p]=0; } }
注意在Splay和RotateTo的过程中都有可能要
<6>区间插入
直接套用build 来建一个新子树
void insert(){ int pos,m; scanf("%d %d",&pos,&m); for(int i=1;i<=m;i++)scanf("%d",&A[i]); rotateTo(pos,0); rotateTo(pos+1,root); build(1,m,key,ch[root][1]);//直接使用build来构建 up(ch[root][1]);up(root); }
<7>区间删除
为了使内存更优,我们用一个stk 收集被删除的节点
void Dfs_del(int k){ stk[++top]=k; if(ch[k][0])Dfs_del(ch[k][0]); if(ch[k][1])Dfs_del(ch[k][1]); } void delt(){ int pos,m; scanf("%d %d",&pos,&m); selc(pos,pos+m-1); Dfs_del(key); key=0; up(ch[root][1]);up(root); }
全家福
#include<bits/stdc++.h>using namespace std;const int M=600005,INF=1e9;int A[M],n,m;struct SplayT{ #define key ch[ch[root][1]][0] int val[M],sz[M],par[M],ch[M][2]; bool rev[M],cov[M]; int stk[M],top; int mx[M],lsum[M],rsum[M],sum[M]; int num,root; void New(int &id,int f,int v){ if(top)id=stk[top--]; else id=++num; val[id]=v;ch[id][0]=ch[id][1]=0;par[id]=f; sum[id]=0;sz[id]=1; cov[id]=rev[id]=0; mx[id]=lsum[id]=rsum[id]=v; } void down_c(int p,int c){ cov[p]=1;val[p]=c; sum[p]=sz[p]*c; mx[p]=lsum[p]=rsum[p]=max(c,sum[p]); } void down_r(int p){ rev[p]^=1; swap(ch[p][0],ch[p][1]); swap(lsum[p],rsum[p]); } void up(int p){ sum[p]=val[p]; sz[p]=1; int l=ch[p][0],r=ch[p][1]; sum[p]+=sum[l]+sum[r]; sz[p]+=sz[l]+sz[r]; mx[p]=max(max(mx[l],mx[r]),max(0,rsum[l])+val[p]+max(lsum[r],0)); lsum[p]=max(lsum[l],sum[l]+val[p]+max(lsum[r],0)); rsum[p]=max(rsum[r],sum[r]+val[p]+max(rsum[l],0)); } void down(int p){ int l=ch[p][0],r=ch[p][1]; if(rev[p]){ if(l)down_r(l); if(r)down_r(r); rev[p]=0; } if(cov[p]){ if(l)down_c(l,val[p]); if(r)down_c(r,val[p]); cov[p]=0; } } void build(int l,int r,int &id,int f){ if(l>r)return; int mid=(l+r)>>1; New(id,f,A[mid]); build(l,mid-1,ch[id][0],id); build(mid+1,r,ch[id][1],id); up(id); } void init(int n){ ch[0][0]=ch[0][1]=sz[0]=par[0]=0; //初始化空地址 sum[0]=0;val[0]=0;mx[0]=lsum[0]=rsum[0]=-INF; rev[0]=cov[0]=0; root=0;num=0;top=0; New(root,0,-INF);//0 New(ch[root][1],root,-INF);//n+1 for(int i=1;i<=n;i++)scanf("%d",&A[i]); build(1,n,ch[ch[root][1]][0],ch[root][1]); up(ch[root][1]); up(root); } void Splay(int x,int goal=0){ while(par[x]!=goal){ int y=par[x]; if(par[y]!=goal){ if(ch[par[y]][0]==y^ch[y][0]==x)rotate(x); else rotate(y); }rotate(x); }up(x); if(!goal)root=x; } void rotateTo(int k,int goal){ int cur=root; down(cur); while(sz[ch[cur][0]]!=k){ if(sz[ch[cur][0]]>k)cur=ch[cur][0]; else k-=1+sz[ch[cur][0]],cur=ch[cur][1]; down(cur); }Splay(cur,goal); } void rotate(int x){ int y=par[x]; int d=ch[y][0]==x; ch[y][!d]=ch[x][d]; if(ch[x][d])par[ch[x][d]]=y; par[x]=par[y]; if(par[y])ch[par[y]][ch[par[y]][1]==y]=x; ch[x][d]=y; par[y]=x; up(y); } void selc(int l,int r){ rotateTo(l-1,0); rotateTo(r+1,root); } void reverse(){ int l,c; scanf("%d %d",&l,&c); selc(l,c+l-1); down_r(key); up(ch[root][1]);up(root);//操作完了搜集信息 } void mark_same(){ int l,c,x; scanf("%d %d %d",&l,&c,&x); selc(l,c+l-1); down_c(key,x); up(ch[root][1]);up(root); } void get_Sum(){ int l,c; scanf("%d %d",&l,&c); selc(l,c+l-1); printf("%d\n",sum[key]); } void Dfs_del(int k){ stk[++top]=k; if(ch[k][0])Dfs_del(ch[k][0]); if(ch[k][1])Dfs_del(ch[k][1]); } void delt(){ int pos,m; scanf("%d %d",&pos,&m); selc(pos,pos+m-1); Dfs_del(key); key=0; up(ch[root][1]);up(root); } void insert(){ int pos,m; scanf("%d %d",&pos,&m); for(int i=1;i<=m;i++)scanf("%d",&A[i]); rotateTo(pos,0); rotateTo(pos+1,root); build(1,m,key,ch[root][1]);//直接使用build来构建 up(ch[root][1]);up(root); } void get_max(){ printf("%d\n",mx[root]); }}T;void solve(){ scanf("%d %d",&n,&m); char s[215]; T.init(n); for(int i=1;i<=m;i++){ scanf("%s",s); if(s[0]=='I')T.insert(); if(s[0]=='M'){ if(s[2]=='X')T.get_max(); else T.mark_same(); }if(s[0]=='D')T.delt(); if(s[0]=='R')T.reverse(); if(s[0]=='G')T.get_Sum(); }}int main(){ solve(); return 0;}
1 0
- Splay专题
- splay专题
- splay专题
- splay专题复习——bzoj 3224 & 1862 & 1503 题解
- SPLAY
- splay
- splay
- splay
- Splay
- Splay
- splay
- splay
- splay
- splay
- Splay
- splay
- Splay
- splay
- MVC
- 蓝桥杯压缩变换
- Java图形操作界面之单选操作
- const 和 static的用法及作用
- 一维数组 与指针 sizeof strlen int char
- Splay专题
- hibernate框架常见异常集锦
- Openstack容器化部署实现及参考
- Problem F: STL——集合运算
- unity各种脚本模块
- 浅析C++标准库与boost库中的智能指针
- 关于游戏盈利点的思考(玩家角度)
- 【干货精选】2016传媒老跟班微博精选内容汇总
- 穷举法解题:一筐鸡蛋,一个一个拿