洛谷P1438 无聊的数列

洛谷P1438 无聊的数列

题目描述

维护一个数列 \({a_i}\),支持两种操作:

1、\(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) \times D\)

2、\(2\) \(P\):询问序列的第\(P\)个数的值\(a_P\)

输入输出格式

输入格式:

第一行两个整数数\(n\)\(m\),表示数列长度和操作个数。
第二行\(n\)个整数,第i个数表示\(a_i\) \((i=1,2,3…,n)\)
接下来的\(m\)行,表示\(m\)个操作,有两种形式:
\(1\) \(L\) \(R\) \(K\) \(D\)
\(2\) \(P\) 字母意义见描述 \((L \leq R)\)

输出格式:

对于每个询问,输出答案,每个答案占一行。

思路

线段度区间维护
首先,根据等差数列,我们可以想到差分
用线段树维护一个原数列的差分数列
\([x,y]\)加一个\(a\)为首项,\(d\)为公差的等差数列的操作就可以分为以下三个操作

  1. 在差分数列的第\(x\)项加\(a\)
  2. 在差分数列的第\([x+1,y]\)项区间整体加上\(d\)
  3. 在差分数列的第\(y+1\)项减去\(a+d(y-x)\)

Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAXN 100010
struct T{
    int l,r,val,addval;
    T(){}
}tr[MAXN<<2];
int nums[MAXN];
int i,j,k,m,n,x,y,a,d;
char readc;
short signal;
void read(int &n){
    signal=1;
    while((readc=getchar())<48||readc>57) if(readc=='-') signal=-1;
    n=readc-48;
    while((readc=getchar())>=48&&readc<=57) n=n*10+readc-48;
    n*=signal;
}
void build(int r,int s,int e){
    if(s==e){
        tr[r].l=tr[r].r=s;
        tr[r].val=nums[s];
        tr[r].addval=0;
        return;
    }
    tr[r].l=s,tr[r].r=e;
    tr[r].addval=0;
    int mid=(s+e)>>1;
    build(r<<1,s,mid),build((r<<1)+1,mid+1,e);
    tr[r].val=tr[r<<1].val+tr[(r<<1)+1].val;
}
void pushdown(int r){
    if(tr[r].addval){
        tr[r<<1].val+=tr[r].addval*(tr[r<<1].r-tr[r<<1].l+1),tr[(r<<1)+1].val+=tr[r].addval*(tr[(r<<1)+1].r-tr[(r<<1)+1].l+1);
        tr[r<<1].addval+=tr[r].addval,tr[(r<<1)+1].addval+=tr[r].addval;
        tr[r].addval=0;
    }
}
void update(int r,int us,int ue,int ns,int ne,int addval){
    if(ne<us||ns>ue) return;
    if(us<=ns&&ue>=ne){
        tr[r].val+=addval*(tr[r].r-tr[r].l+1);
        tr[r].addval+=addval;
        return;
    }
    pushdown(r);
    int mid=(ns+ne)>>1;
    update(r<<1,us,ue,ns,mid,addval);
    update((r<<1)+1,us,ue,mid+1,ne,addval);
    tr[r].val=tr[r<<1].val+tr[(r<<1)+1].val;
}
int query(int r,int qs,int qe,int ns,int ne){
    if(ns>qe||ne<qs) return 0;
    if(qs<=ns&&qe>=ne) return tr[r].val;
    pushdown(r);
    int mid=(ns+ne)>>1;
    return query(r<<1,qs,qe,ns,mid)+query((r<<1)+1,qs,qe,mid+1,ne);
}
int main(){
#ifndef ONLINE_JUDGE
    freopen("test.in","r",stdin);
    freopen("test.out","w",stdout);
#endif
    read(n),read(m);
    for(i=1;i<=n;i++) read(nums[i]);
    for(i=n;i>=1;i--) nums[i]=nums[i]-nums[i-1];
    build(1,1,n);
    for(i=1;i<=m;i++){
        read(k);
        if(k==1){
            read(x),read(y),read(a),read(d);
            update(1,x,x,1,n,a);
            if(x+1<=y) update(1,x+1,y,1,n,d);
            if(y+1<=n) update(1,y+1,y+1,1,n,-(a+d*(y-x)));
        }else{
            read(x);
            printf("%d\n",query(1,1,x,1,n));
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/linxif2008/p/10279726.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值