题目在这里
这应该是splay裸题了吧。对于每个节点保存5个值,size,_max,flag,lazy,val 分别表示这个节点的子树大小,子树的最大值,子树是否有打过翻转标记,子树的增加的值,(前面的所有都包括这个节点它自己),以及这个节点的当前值。对于一段区间[L,R]的询问/修改,只需把L-1这个节点旋转到根,再把R+1这个节点旋转到根的右儿子。这样R+1节点的左子树就对应[L,R]这个区间,之后就直接在它的左儿子上打标记/询问就行了。当然为了方便新建两个节点一个代表0,另一个代表n+1。(好像学名叫僵尸节点。。。)对于Add操作,直接所有值加v;而对于翻转操作,直接交换这个节点的左右儿子就行了(大概意会一下)。注意这样搞完之后,下标为i的节点不一定代表s[i],而是要根据二叉查找树的定义查找(比如当前找第k个点,如果左子树大小小于k-1就往左子树里找,如果等于k-1就是它自己,如果大于k-1就k-=size[lson[x]],然后往右子树里找)。pushdown操作类比一下线段树,即只要到这个点就把它的pushdown下去,然后把这个点的标记清空。然后每次干完之后update一下(注意最大值还要跟当前的val比较)。这样应该就差不多了。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <deque>
#include <queue>
#include <map>
#include <set>
#include <ctime>
using namespace std;
const int MAXN=50005,INF=(1<<29);
int n,m,root;
class Splay_Tree
{
int fa[MAXN],ch[MAXN][2],size[MAXN],_max[MAXN],val[MAXN],lazy[MAXN]; bool turn[MAXN];
void modify(int x) { if (x==0) return; turn[x]^=1; }
void Add(int x,int v) { if (x==0) return; _max[x]+=v,val[x]+=v,lazy[x]+=v; }
void update(int x)
{
int l=ch[x][0],r=ch[x][1]; size[x]=1,_max[x]=val[x];
if (l) size[x]+=size[l],_max[x]=max(_max[x],_max[l]);
if (r) size[x]+=size[r],_max[x]=max(_max[x],_max[r]);
}
void pushdown(int x)
{
if (lazy[x]) Add(ch[x][0],lazy[x]),Add(ch[x][1],lazy[x]),lazy[x]=0;
if (turn[x]) swap(ch[x][0],ch[x][1]),modify(ch[x][0]),modify(ch[x][1]),turn[x]=false;
}
void Rotate(int x,int d)
{
int y=fa[x],z=fa[y]; ch[y][d^1]=ch[x][d],fa[ch[x][d]]=y;
if (z) ch[z][ch[z][1]==y]=x; fa[x]=z,ch[x][d]=y,fa[y]=x;
update(y);
}
void splay(int x,int goal)
{
pushdown(x);
while (fa[x]!=goal)
{
int y=fa[x],z=fa[y];
if (z==goal) Rotate(x,ch[y][0]==x);
else
{
int f=(ch[z][0]==y);
if (ch[y][f^1]==x) Rotate(y,f),Rotate(x,f); else Rotate(x,f^1),Rotate(x,f);
}
}
update(x);
if (goal==0) root=x;
}
int Find(int x)
{
int nowx=root; pushdown(nowx);
while (size[ch[nowx][0]]+1!=x)
{
if (size[ch[nowx][0]]+1<x) x-=size[ch[nowx][0]]+1,nowx=ch[nowx][1];else nowx=ch[nowx][0];
pushdown(nowx);
}
return nowx;
}
public:
void Build_Tree(int l,int r,int f)
{
if (l>r) return;
int mid=(l+r)>>1;
if (f) fa[mid]=f,ch[f][mid>f]=mid;else root=mid,fa[mid]=0;
val[mid]=0,_max[mid]=0,lazy[mid]=0,size[mid]=1;
Build_Tree(l,mid-1,mid),Build_Tree(mid+1,r,mid); update(mid);
}
void modify(int Ql,int Qr)
{
int keyx=select(Ql+1,Qr+1);
modify(keyx); splay(keyx,0);
}
void Add(int Ql,int Qr,int v)
{
int keyx=select(Ql+1,Qr+1);
Add(keyx,v); splay(keyx,0);
}
void Query(int Ql,int Qr)
{
int keyx=select(Ql+1,Qr+1);
printf("%d\n",_max[keyx]);
splay(keyx,0);
}
int select(int Ql,int Qr)
{
int L=Find(Ql-1),R=Find(Qr+1);
splay(L,0),splay(R,L);
return ch[R][0];
}
/*void debug(int x)
{
printf("No.%d size=%d max=%d val=%d lazy=%d ls=%d rs=%d\n ",x,size[x],_max[x],val[x],lazy[x],
ch[x][0],ch[x][1]);
if (ch[x][0]) debug(ch[x][0]);
if (ch[x][1]) debug(ch[x][1]);
}*/
}T;
int Get()
{
char ch; int v=0; bool f=false;
while (!isdigit(ch=getchar())) if (ch=='-') f=true; v=ch-48;
while (isdigit(ch=getchar())) v=v*10+ch-48;
if (f) return -v;else return v;
}
int main()
{
//freopen("terminator.in","r",stdin);
//freopen("terminator.out","w",stdout);
n=Get(),m=Get(); int type,l,r,v;
T.Build_Tree(1,n+2,0);
while (m--)
{
type=Get(),l=Get(),r=Get();
if (type==1) v=Get(),T.Add(l,r,v);
if (type==2) T.modify(l,r);
if (type==3) T.Query(l,r);
}
return 0;
}