P1438 无聊的数列

区间问题,肯定是线段树了,但是区间加的是一个等差数列,怎么办呢

我们可以通过差分来维护。

蛤是差分?

搞一个数组专门差分,在数组中记录对于l~r的区间加x,在l位置加上x,在r+1位置减去x。

当查询某个数值时,该位置上的数加上差分数组中1~该位置的前缀和,自己出组数试一下发现这样是对的

我们线段树刚好可以区间修改和区间求和,所以这题要用到线段树维护差分

对于首项,我们在线段树的l位置直接加首项,在l+1~r位置区间修改,每个位置加上d,在r+1位置减去等差数组中

的最后一项也就是a1+(r-l)d,这样我们的区间加等差数列就维护好了。

单点查询时,查询线段树中1~l的值加上原数组中a[l]的值。

然后特别注意的是r+1>n的情况我们不必再修改,会RE

对于l+1>r的情况,只需在l位置加上首项,l+1位置减去首项。

#include<iostream>
#include<cstdio>
#define lson k<<1,l,mid
#define rson k<<1|1,mid+1,r
#define ls k<<1
#define rs k<<1|1
#define sum(rt) tr[rt].sum
#define laz(rt) tr[rt].laz
#define mid ((l+r)>>1)
using namespace std;
const int maxn=100005;
int n,m,a[maxn];
struct node{
    int sum,laz;
}tr[maxn<<2];
inline int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
    return s*w;
}
inline void update(int k){
    sum(k)=sum(ls)+sum(rs);
}
inline void down(int k,int l,int r){
    sum(ls)+=laz(k)*(mid-l+1);
    laz(ls)+=laz(k);
    sum(rs)+=laz(k)*(r-mid);
    laz(rs)+=laz(k);
    laz(k)=0;
}
void change(int k,int l,int r,int x,int y,int val){
    if(x<=l&&y>=r){
        sum(k)+=val*(r-l+1);
        laz(k)+=val;
        return ;
    }
    if(laz(k)!=0)down(k,l,r);
    if(x<=mid)change(lson,x,y,val);
    if(y>mid)change(rson,x,y,val);
    update(k);
}
int ask(int k,int l,int r,int x,int y){
    if(l==x&&y==r){
        return sum(k);
    }
    if(laz(k)!=0)down(k,l,r);
    if(y<=mid)return ask(lson,x,y);
    else if(x>mid)return ask(rson,x,y);
    else return ask(lson,x,mid)+ask(rson,mid+1,y);
}
int main(){
    n=read();m=read();
    for(int i=1;i<=n;++i)
        a[i]=read();
    int opt,l,r,k,d;
    while(m--){
        opt=read();
        if(opt==1){
            l=read();r=read();k=read();d=read();
            change(1,1,n,l,l,k);
            if(l!=r)change(1,1,n,l+1,r,d);
            if(r+1<=n)change(1,1,n,r+1,r+1,-(k+(r-l)*d));
        }
        else {
            l=read();
            printf("%d\n",ask(1,1,n,1,l)+a[l]);
        }
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/sanjinliushi/p/11567445.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值