洛谷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\)为公差的等差数列的操作就可以分为以下三个操作
- 在差分数列的第\(x\)项加\(a\)
- 在差分数列的第\([x+1,y]\)项区间整体加上\(d\)
- 在差分数列的第\(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;
}