��վ�ܷ�������

线段树——维护等差序列

题目描述

维护一个数列${a[i]}$,支持两种操作:
1、$ L, R, K, D$:给出一个长度等于$R-L+1$的等差数列,首项为$K$,公差为$D$,并将它对应加到$a[L]~a[R]$的每一个数上。即:令$a[L]=a[L]+K$,$a[L+1]=a[L+1]+K+D+….+a[L+2]=a[L+2]+K+2D……a[R]=a[R]+K+(R-L)D$
2、 $P$:询问序列的第$P$个数的值$a[P]$。

解决方案

其实我已开始看到题我又是一脸懵逼:
什么???等差数列??这怎么维护???
分块??不行吧??
然后。。我参考了题解,因为差分我的真的没什么经验,我没怎么碰到过这种题;
因为等差数列易知$a[i]-a[i-1]=d$是定值;
利用差分前缀和的思想

$data$ $l$ $l+1$ $l+2$ $·······$ $r-1$ $r$ $r+1$
$sum$ $k$ $d$ $d$ $d$ $d$ $d$ $-(k+(r-l)*d)$

一求前缀和,就可以发现刚好l-r能加上等差数列了!
要求$a[x]$,直接输出$data[i]+sum[1]+sum[2]+…+sum[x]$;
于是就变成了线段树模板
普通的修改和查询
但是要注意一些细节,不要越界操作了

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define rson 2*p
#define lson 2*p+1
#define N 200000+100
using namespace std;
struct node
{
    int lt;
    int rt;
    int val;
    int sum;
}a[4*N];
int n,m,data[N],cha[N];
void pushup(int p)
{
   a[p].sum=a[2*p].sum+a[2*p+1].sum;
}
void build(int p,int l,int r)
{
    a[p].lt=l;
    a[p].rt=r;
    if(l==r){a[p].sum=0;return;}
    int mid=(l+r)/2;
    build(2*p,l,mid);
    build(2*p+1,mid+1,r);
   pushup(p);
}
void pushdown(int p)
{
     if(a[p].val!=0)
    {
        a[2*p].val+=a[p].val;
        a[2*p].sum+=(a[2*p].rt-a[2*p].lt+1)*a[p].val;
        a[2*p+1].val+=a[p].val;
        a[2*p+1].sum+=(a[2*p+1].rt-a[2*p+1].lt+1)*a[p].val;
        a[p].val=0;
    }

}
void update(int p,int l,int r,int d)
{
    if(a[p].lt==l&&a[p].rt==r){a[p].val+=d;a[p].sum+=(r-l+1)*d;return;}
    pushdown(p);
    int mid=(a[p].lt+a[p].rt)/2;
    if(r<=mid)update(2*p,l,r,d);
    else if(l>mid)update(2*p+1,l,r,d);
    else {update(2*p,l,mid,d);update(2*p+1,mid+1,r,d);}
   pushup(p);
}
int query(int p,int l,int r)
{
    if(a[p].lt==l&&a[p].rt==r)return a[p].sum;
    pushdown(p);
    int mid=(a[p].lt+a[p].rt)/2;
    if(r<=mid)return query(2*p,l,r);
    else if(l>mid)return query(2*p+1,l,r);
    else return query(2*p,l,mid)+query(2*p+1,mid+1,r);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&data[i]);
    build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        int op,x,y,k,d;
        scanf("%d",&op);
        if(op==1)
        {
            scanf("%d%d%d%d",&x,&y,&k,&d);
            if(x==y)//注意特判
            {
                update(1,x,y,k);
                if(x+1>n)continue;//注意不要越界
                update(1,x+1,x+1,-k);
                continue;
            }
            update(1,x+1,y,d);
            update(1,x,x,k);
            if(y+1>n)continue;//不要越界
            update(1,y+1,y+1,-(k+d*(y-x)));
        }
        else
        {
            scanf("%d",&x);
            printf("%d\n",data[x]+query(1,1,x));
        }

    }
    return 0;
}