洛谷 【P1438】无聊的数列
线段树上添加等差数列(简易版)
意义:
一个数组,M个操作,分为两种:
1、在[l,r]区间之内添加等差数列
2、在查询 r 点经过一系列变化后的结果
思路:
添加:在树上将一个等差数列分为几个连续的等差数列,添加到线段树中。
查询:查询点所在的所有区间的值,相加sum +=(r - tree[step].l)* d + k。
#include <cstdio>
using namespace std;
const int MAXN = 1e5+5;
struct node{
int l,r;
int a,d;
}tree[MAXN<<2];
int num[MAXN];
void Build(int l,int r,int step){
tree[step].l=l;
tree[step].r=r;
tree[step].a=0;
tree[step].d=0;
if(l==r){
return;
}
int mid=(l+r)>>1;
Build(l,mid,step<<1);
Build(mid+1,r,step<<1|1);
}
void Add(int l,int r,int a,int d,int step){
if(tree[step].l>r||tree[step].r<l)return;
if(tree[step].l>=l&&tree[step].r<=r){
tree[step].a+=(a+(tree[step].l-l)*d);
tree[step].d+=d;
return;
}
Add(l,r,a,d,step<<1|1);
Add(l,r,a,d,step<<1);
}
int sum;
void Query(int q,int step){
if(tree[step].l>q||tree[step].r<q)return;
sum+=(q-tree[step].l)*tree[step].d+tree[step].a;
Query(q,step<<1);
Query(q,step<<1|1);
}
int main(){
int N,M;
scanf("%d%d",&N,&M);
Build(1,N,1);
for(int i=0;i<N;i++){
scanf("%d",&num[i]);
}
while(M--){
int opr;
scanf("%d",&opr);
if(opr==1){
int l,r,a,d;
scanf("%d%d%d%d",&l,&r,&a,&d);
Add(l,r,a,d,1);
}
else{
int r;
scanf("%d",&r);
sum=0;
Query(r,1);
printf("%d\n",sum+num[r-1]);
}
}
return 0;
}