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。
Input
第一行两个整数N,M。M为操作个数。
以下M行,每行最多四个整数,依次为K,L,R,V。
K表示是第几种操作,如果不是第1种操作则K后面只有两个数。
Output
对于每个第3种操作,给出正确的回答。
Sample Input
4 4
1 1 3 2
1 2 4 -1
2 1 3
3 2 4
1 1 3 2
1 2 4 -1
2 1 3
3 2 4
Sample Output
2
【数据范围】
N<=50000,M<=100000。
【数据范围】
N<=50000,M<=100000。
题解Here!
刚开始学Splay时,我也是一脸懵——区间翻转咋整?
然后,我先去做了个更难的题目:BZOJ1500: [NOI2005]维修数列
于是就会做这题了。。。
区间 [ l , r ] 翻转也就是将 l-1 伸展到根,将 r+1 伸展到 l-1 的右子树,然后对 r+1 的左子树,即 [ l , r ] 这段区间打上一个区间翻转标记flag。
下次伸展之前把标记下传一下就好了。
区间加同理。
附代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#define MAXN 50010
#define MAX 2147483647
using namespace std;
int n,m,root,w[MAXN];
struct node{
int son[2];
int f,v,s,flag,c;
}a[MAXN];
inline int read(){
int date=0,w=1;char c=0;
while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
return date*w;
}
inline void pushup(int rt){
if(!rt)return;
a[rt].s=a[a[rt].son[0]].s+a[a[rt].son[1]].s+1;
a[rt].v=max(w[rt],max(a[a[rt].son[0]].v,a[a[rt].son[1]].v));
}
inline void pushdown(int rt){
if(!rt)return;
if(a[rt].c){
if(a[rt].son[0]){a[a[rt].son[0]].c+=a[rt].c;a[a[rt].son[0]].v+=a[rt].c;w[a[rt].son[0]]+=a[rt].c;}
if(a[rt].son[1]){a[a[rt].son[1]].c+=a[rt].c;a[a[rt].son[1]].v+=a[rt].c;w[a[rt].son[1]]+=a[rt].c;}
a[rt].c=0;
}
if(a[rt].flag){
a[a[rt].son[0]].flag^=1;a[a[rt].son[1]].flag^=1;a[rt].flag=0;
swap(a[rt].son[0],a[rt].son[1]);
}
}
inline void turn(int rt,int k){
int x=a[rt].f,y=a[x].f;
pushdown(x);pushdown(rt);
a[x].son[!k]=a[rt].son[k];
if(a[rt].son[k])a[a[rt].son[k]].f=x;
a[rt].f=y;
if(y)a[y].son[a[y].son[1]==x]=rt;
a[x].f=rt;
a[rt].son[k]=x;
pushup(x);pushup(rt);
}
void splay(int rt,int ancestry){
while(a[rt].f!=ancestry){
int x=a[rt].f,y=a[x].f;
if(y==ancestry)turn(rt,a[x].son[0]==rt);
else{
int k=a[y].son[0]==x?1:0;
if(a[x].son[k]==rt){turn(rt,!k);turn(rt,k);}
else{turn(x,k);turn(rt,k);}
}
}
if(ancestry==0)root=rt;
pushup(rt);
}
int buildtree(int l,int r,int rt){
if(l>r)return 0;
int mid;
if(l==r){
a[l].f=rt;
a[l].s=1;
return l;
}
mid=l+r>>1;
a[mid].son[0]=buildtree(l,mid-1,mid);
a[mid].son[1]=buildtree(mid+1,r,mid);
a[mid].f=rt;a[mid].s=1;
pushup(mid);
return mid;
}
int kth(int rt,int x){
pushdown(rt);
int lsons=0;
if(a[rt].son[0])lsons=a[a[rt].son[0]].s;
if(x==lsons+1)return rt;
if(x<=lsons)return kth(a[rt].son[0],x);
else return kth(a[rt].son[1],x-lsons-1);
}
int split(int rt,int x,int y){
int p=kth(rt,x),q=kth(rt,y);
splay(p,0);splay(q,p);
return a[q].son[0];
}
void work(int rt,int x,int y,int k){
int p=kth(rt,x),q=kth(rt,y+2),r;
splay(p,0);splay(q,p);
r=a[q].son[0];
a[r].c+=k;a[r].v+=k;w[r]+=k;
pushup(q);pushup(p);
}
int main(){
int f,x,y,k;
n=read();m=read();
a[0].v=w[0]=w[1]=w[n+2]=-MAX;
root=buildtree(1,n+2,0);
while(m--){
f=read();x=read();y=read();
switch(f){
case 1:{
k=read();
work(root,x,y,k);
break;
}
case 2:{
k=split(root,x,y+2);
a[k].flag^=1;
break;
}
case 3:{
k=split(root,x,y+2);
printf("%d\n",a[k].v);
break;
}
}
}
return 0;
}