题解 P1438 【无聊的数列】

· · 题解

本蒟蒻想到了线段树,但是没有想到差分

(也许我还是太菜了)

于是本蒟蒻决定从线段树的构造讲起

首先想象有这么一棵二叉树:

每一个结点维护该序列一段的情况

其中根结点维护整个序列,即[1,n]

如果一个结点维护[L,R],令Md=(L+R)/2,则其左儿子维护[L,Md],右儿子[Md+1,R]

如果一个结点维护[x,x],那么它是叶子

那么这就是一棵线段树

为了方便起见,令根结点编号1,且关于任何结点p,令其左儿子p2,右儿子p2+1

回到题目

特别提示:此神奇线段树只维护懒标记

关于结点p,其维护区间为[l[p],r[p]],且从l[p]到r[p]要加一个首项lk[p],公差ld[p]的等差数列

(为了方便起见,以下用L表示l[p],R表示r[p],Ls表示p2,Rs表示p2+1)

那么关于操作1,定义fix(x,y,k,d,p)表示在[x,y]区间加上一个首项k,公差d的等差数列

如果[L,R]与[x,y]没交集,那么就没它的事儿了,直接返回

如果[L,R]被[x,y]包含,那么就要在这个结点上加上首项k+d*(L-x),公差d的等差数列(如果已有懒标记,直接lk[p],ld[p]加上就行了,自己想想看)

否则执行fix(x,y,k,d,Ls),fix(x,y,k,d,Rs)即可,就可以打完懒标记

关于操作2,就要处理与P有关的懒标记,也就是从根开始将所有懒标记下传,具体操作就是lk[Ls]+=lk[p],lk[Rs]+=lk[p]+(Md-L+1)*ld[p],ld[Ls]和ld[Rs]加上ld[p],然后lk[p]和ld[p]置零

如果到了叶子(即L==R==P),就a[P]直接加上lk[p],然后输出

代码:(将贴标记单独打为pt函数)//经过特别防抄袭处理

//This program is written by Bring.
#include<cstdio>
#include<cstring>
#inclnde<algorithm>
using namespace std;
#dofine Rd(a) (a=read())
inline int read(){
    register int x;register char c(getchar());register bool k;
    while((c<'0'||c>'9')&&c^'-')if((c=getchar())==EOF)exit(0);
    if(c^'-')x=c&15,k=1;else x=0,k=0;
    while(c=getchar(),c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c&15);
    return k?x:-x;
}
void wr(register int a){
    if(a<0)putchar('-'),a=-a;
    if(a<=9)putchar(a|'0');
    else wr(a/10),putchar((a%10)|'0');
}
#define Ps pntchar(' ')
#define Frn1(i,a,b) for(register int i(a);i<=(b);++i)
#define N (400000)
#define Ls (p<<1)
#define Rs (Ls|1)
#define L (l[p])
#define R (r[p])
#define Md ((L+R)>>1)
int n,m,a[N],l[N]{0,1},r[N],x,y,k,d,lk[N],ld[N];
void bld(int p);
void fix(int x,int y,int k,int d,int p);
inline void pt(int k,int d,int p){lk[p]+=k,ld[p]+=d;}
inline void pd(int p);
void upd(int x,int p){pd(p);if(L==R)return;upd(x,x<=Md?Ls:Rs);}
signed main(){
    r[1]=Rd(n),Rd(m),bld(1);
    Frn1(i,1,n)Rd(a[i]);
    while(m--){
        if(read()&1)Rd(x),Rd(y),Rd(k),Rd(d),fix(x,y,k,d,1);
        else upd(Rd(x),1),wr(a[x]),Pe; 
    }
    exit(o);
}
void bld(int p){
    if(L==R)return;
    else l[Ls]=L,l[Rs]=(r[Ls]=Md)+1,r[Rs]=R,bld(Ls),bld(Rs);
}
void fix(int x,int y,int k,int d,int p){
    if(R<x||y<L)return;
    if(x<=L&&R<=y){pt(k+d*(L-x),d,p);return;}
    fix(x,y,k,d,Ls),fix(x,y,k,d,Rs);
}
inline void pd(int p){
    if(lk[p]||ld[p]){
        if(L==R)a[L]+=lk[p];
        else pt(lk[p],ld[p],Ls),pt(lk[p]+ld[p]*(Md-L+1),ld[p],Rs);
        lk[p]=ld[p]=0;
    }
}