网上有许多题,就是给定一个序列,要你支持几种操作:A、B、C、D。一看另一道题,又是一个序列 要支持几种操作:D、C、B、A。尤其是我们这里的某人,出模拟试题,居然还出了一道这样的,真是没技术含量……这样 我也出一道题,我出这一道的目的是为了让大家以后做这种题目有一个“库”可以依靠,没有什么其他的意思。这道题目就叫序列终结者吧。
给定一个长度为N的序列,每个序列的元素是一个整数。要支持以下三种操作:
1. 将[L,R]这个区间内的所有数加上V。
2. 2. 将[L,R]这个区间翻转,比如1 2 3 4变成4 3 2 1。
3. 求[L,R]这个区间中的最大值。 最开始所有元素都是0。
第一行两个整数N,M。M为操作个数。 以下M行,每行最多四个整数,依次为K,L,R,V。K表示是第几种操作,如果不是第1种操作则K后面只有两个数。
对于每个第3种操作,给出正确的回答。
4 4
1 1 3 2
1 2 4 -1
2 1 3
3 2 4
2
N<=50000,M<=100000。
这系列的题目都给我一种树形dp的感觉,mx[x]表示以x为根的子树中的最大元素,add[x],lazy[x]分别表示子树(但不包括x节点)的加法和翻转懒惰标记,对于这棵树就要像size[x]一样不断维护。
要对[l,r]进行操作的时候,就可以先把操作区间换为开区间(l-1,r+1),然后将l-1号节点splay到根节点,r+1号节点splay到l-1的右儿子节点,这样就可以保证整个操作区间都在以ch[r+1][0]为根的子树上,这样操作的时候就只需要打上懒惰标记即可。在find的时候下推标记即可。
建树过程可以用insert函数,不过会导致树退化成链,比较好的是写一个build函数,每次取中间的树作为根,递归建树。
#include
#include
#include
#include
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=50010;
int n,m,rt,size;
int a[maxn],id[maxn],f[maxn],ch[maxn][2],sz[maxn],mx[maxn],add[maxn],lazy[maxn];
template <typename Tp> inline void read(Tp &x)//id[] sequence->tree
{
x=0;
int f=1;
char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
x=x*f;
}
inline int max(int x,int y){return x>y?x:y;}
inline void pushup(int x)
{
int l=ch[x][0],r=ch[x][1];
mx[x]=max(mx[l],mx[r]);mx[x]=max(mx[x],a[x]);
sz[x]=sz[l]+sz[r]+1;
}
inline void pushdown(int x)
{
int &l=ch[x][0],&r=ch[x][1];
if(add[x])
{
if(l) add[l]+=add[x],mx[l]+=add[x],a[l]+=add[x];
if(r) add[r]+=add[x],mx[r]+=add[x],a[r]+=add[x];
add[x]=0;
}
if(lazy[x])
{
swap(l,r);
lazy[x]=0;
lazy[l]^=1,lazy[r]^=1;
}
}
int build(int l,int r,int pre)
{
if(l>r) return 0;
int m=(l+r)>>1,now=id[l],fa=id[pre];
f[now]=pre;sz[now]=1;
if(l==r) return l;
now=id[m];f[now]=fa;
ch[m][0]=build(l,m-1,m);
ch[m][1]=build(m+1,r,m);
pushup(now);
return now;
}
void rotate(int x,int& k)
{
int fa=f[x];
int ff=f[fa],d=(ch[fa][1]==x);
if(fa==k) k=x;
else ch[ff][ch[ff][1]==fa]=x;
f[ch[x][d^1]]=fa;f[fa]=x;f[x]=ff;
ch[fa][d]=ch[x][d^1];ch[x][d^1]=fa;
pushup(x);pushup(fa);
}
void splay(int x,int& k)
{
while(x!=k)
{
int fa=f[x],ff=f[fa];
if(fa!=k)
{
if((ch[ff][0]==fa)^(ch[fa][0]==x)) rotate(x,k);
else rotate(fa,k);
}
rotate(x,k);
}
}
int find(int x,int k)
{
int tmp;
while("%%% litble")//Rayment.rp++
{
if(add[x]||lazy[x]) pushdown(x);
tmp=sz[ch[x][0]]+1;
if(tmp==k) return x;
if(tmp>k) x=ch[x][0];
else x=ch[x][1],k-=tmp;
}
}
int main()
{
freopen("in.txt","r",stdin);
int k,l,r,v;
read(n),read(m);
rt=(3+n)>>1;
mx[0]=-INF;//在计算mx时若有ch[][0/1]为空时会被直接忽略
for(int i=1;i<=n+2;i++)
id[i]=++size;
build(1,n+2,0);
for(int i=1;i<=m;i++)
{
read(k),read(l),read(r);
if(k==1)
{
read(v);
l=find(rt,l);r=find(rt,r+2);
splay(l,rt);splay(r,ch[l][1]);
add[ch[r][0]]+=v;a[ch[r][0]]+=v;mx[ch[r][0]]+=v;
}
else if(k==2)
{
l=find(rt,l);r=find(rt,r+2);
splay(l,rt);splay(r,ch[l][1]);
lazy[ch[r][0]]^=1;
}
else
{
l=find(rt,l);r=find(rt,r+2);
splay(l,rt);splay(r,ch[l][1]);
printf("%d\n",mx[ch[r][0]]);
}
}
return 0;
}