最大值(最基本splay区间修改,注意小细节)

来源:互联网 发布:华为商务软件 编辑:程序博客网 时间:2024/05/17 22:38

Description

  在N(1<=N<=100000)个数A1…An组成的序列上进行M(1<=M<=100000)次操作,操作有两种:
  (1)1 L R C:表示把A[L]到A[R]增加C(C的绝对值不超过10000);
  (2)2 L R:询问A[L]到A[R]之间的最大值。

Input

  第一行输入N(1<=N<=100000),表示序列的长度,接下来N行输入原始序列;接下来一行输入M(1<=M<=100000)表示操作的次数,接下来M行,每行为1 L R C或2 L R

Output

  对于每个操作(2)输出对应的答案。

Sample Input

5
1
2
3
4
5
3
2 1 4
1 1 3 3
2 3 5

Sample Output

4
6

Data Constraint

Hint

【限制】
  保证序列中的所有的数都在longint范围内

  • 这题最需要注意的地方有:

    • ans[0]的赋值,也就是对于根的赋值.

    • 因为我们为了方便每一次区间操作,把0都设为根,于是在update的时候,很有可能出错.

  • 还要注意的是,我们把0设为根,则开始节点和结束节点分别为2,n+1,故还需第n+2个节点来进行操作.

#include <iostream>#include <cstdio>#include <cstring>#define N 100010#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;int n,m,i,x,y,p,C;int tr[N][2],fa[N],a[N],ans[N],d[N],add[N];void lazy(int x,int y){    a[x]+=y, ans[x]+=y, add[x]+=y;}void update(int x){    ans[x]=max(a[x],max(ans[tr[x][0]],ans[tr[x][1]]));}void clear(int x){    if (tr[x][0]) lazy(tr[x][0],add[x]);    if (tr[x][1]) lazy(tr[x][1],add[x]);    add[x]=0;}void remove(int x,int y){    do{        d[++d[0]]=x, x=fa[x];    } while (x!=y);    while (d[0]) clear(d[d[0]--]);}int son(int x){    return tr[fa[x]][1]==x;}void rotate(int x){    int k=son(x), y=fa[x];    if (tr[x][!k]) fa[tr[x][!k]]=y;    if (fa[y]) tr[fa[y]][son(y)]=x;    fa[x]=fa[y], fa[y]=x, tr[y][k]=tr[x][!k], tr[x][!k]=y;    update(y), update(x);}void splay(int x,int y){    remove(x,y);    while (fa[x]!=y)    {        if (fa[fa[x]]!=y)            if (son(fa[x])==son(x)) rotate(fa[x]); else rotate(x);        rotate(x);    }}int main(){    scanf("%d",&n), ans[0]=-1e9;    fo(i,1,n)        scanf("%d",&a[i+1]), fa[i]=i+1, tr[i+1][0]=i, update(i+1);    fa[n+1]=n+2, tr[n+2][0]=n+1, update(n+2);    for(scanf("%d",&m);m;m--)    {        scanf("%d%d%d",&p,&x,&y), x++, y++, splay(x-1,0), splay(y+1,x-1);        if (p==1) scanf("%d",&C), lazy(tr[y+1][0],C); else printf("%d\n",ans[tr[y+1][0]]);    }}