建树
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的过程中都有可能要 down
<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;
}