Description
网上有许多题,就是给定一个序列,要你支持几种操作:A、B、C、D。一看另一道题,又是一个序列 要支持几种操作:D、C、B、A。尤其是我们这里的某人,出模拟试题,居然还出了一道这样的,真是没技术含量……这样 我也出一道题,我出这一道的目的是为了让大家以后做这种题目有一个“库”可以依靠,没有什么其他的意思。这道题目 就叫序列终结者吧。 给定一个长度为N的序列,每个序列的元素是一个整数(废话)。要支持以下三种操作: 1. 将[L,R]这个区间内的所有数加上V。 2. 将[L,R]这个区间翻转,比如1 2 3 4变成4 3 2 1。 3. 求[L,R]这个区间中的最大值。 最开始所有元素都是0。
N<=50000,M<=100000。
Solution
又sb了,裸的splay调半天。每个人的splay写法都不太一样,这种模板果然还是要自己熟悉
这里用类似线段树的写法建树,两个tag注意push的顺序即可。那一段膜标膜来的remove操作没有什么卵用,实际上tag已经在旋转的时候传掉了。仔细一想这应该是写法的问题,大概我的写法比较优秀
Code
#include <stdio.h>
#include <algorithm>
#include <stack>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
const int INF=0x7fffffff;
const int N=500005;
std:: stack<int> stack;
int son[N][2],lazy[N][2],fa[N];
int size[N],mx[N],a[N],root;
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void push_up(int now) {
mx[now]=std:: max(a[now],std:: max(mx[son[now][0]],mx[son[now][1]]));
size[now]=size[son[now][0]]+size[son[now][1]]+1;
}
void push_down(int now) {
if (lazy[now][1]) {
if (son[now][0]) {
lazy[son[now][0]][1]+=lazy[now][1];
mx[son[now][0]]+=lazy[now][1];
a[son[now][0]]+=lazy[now][1];
}
if (son[now][1]) {
lazy[son[now][1]][1]+=lazy[now][1];
mx[son[now][1]]+=lazy[now][1];
a[son[now][1]]+=lazy[now][1];
}
lazy[now][1]=0;
}
if (lazy[now][0]) {
std:: swap(son[now][0],son[now][1]);
lazy[son[now][0]][0]^=1;
lazy[son[now][1]][0]^=1;
lazy[now][0]^=1;
}
}
void rotate(int x) {
int y=fa[x]; int z=fa[y];
int k=son[y][1]==x;
son[z][son[z][1]==y]=x;
fa[x]=z;
son[y][k]=son[x][!k];
fa[son[x][!k]]=y;
son[x][!k]=y;
fa[y]=x;
push_up(y); push_up(x);
}
/*void remove(int x,int y) {
while (x!=y) {
stack.push(x);
x=fa[x];
}
stack.push(y);
while (!stack.empty()) {
push_down(stack.top());
stack.pop();
}
}*/
void splay(int x,int goal=0) {
// remove(x,goal);
while (fa[x]!=goal) {
int y=fa[x]; int z=fa[y];
if (z!=goal) {
if ((son[z][1]==y)^(son[y][1]==x)) rotate(x);
else rotate(y);
}
rotate(x);
}
if (!goal) root=x;
}
int buildTree(int l,int r) {
int mid=(l+r)>>1;
size[mid]=1; mx[mid]=a[mid];
if (l==r) return mid;
if (l<mid) {
son[mid][0]=buildTree(l,mid-1);
fa[son[mid][0]]=mid;
}
if (mid<r) {
son[mid][1]=buildTree(mid+1,r);
fa[son[mid][1]]=mid;
}
push_up(mid);
return mid;
}
int find(int k) {
int now=root;
while (233) {
push_down(now);
if (size[son[now][0]]+1==k) return now;
else if (size[son[now][0]]+1<k) {
k-=size[son[now][0]]+1;
now=son[now][1];
} else now=son[now][0];
}
}
void operate(int &l,int &r) {
l=find(l); splay(l);
r=find(r+2); splay(r,l);
}
void reverse(int l,int r) {
operate(l,r);
lazy[son[r][0]][0]^=1;
}
void modify(int l,int r,int v) {
operate(l,r);
lazy[son[r][0]][1]+=v;
mx[son[r][0]]+=v;
a[son[r][0]]+=v;
}
int query(int l,int r) {
operate(l,r);
return mx[son[r][0]];
}
int main(void) {
int n=read(),m=read();
a[1]=a[n+2]=mx[0]=-INF;
root=buildTree(1,n+2);
while (m--) {
int opt=read(),l=read(),r=read();
if (opt==1) {
int v=read();
modify(l,r,v);
} else if (opt==2) {
reverse(l,r);
} else if (opt==3) {
printf("%d\n", query(l,r));
}
}
return 0;
}