维护一个序列,支持两种操作:
1.给出一个长度等于r-l+1的等差数列,首项为 k,公差为 d,并将它对应加到 [l,r]范围中的每一个数上。
2.查询第p个数的值。
这道题困难在lazy标记如何处理,首先看出我们需要保存两个值,一个一段区间要加上的等差数列的首项k,另一个是公差d。其次,我们应该发现如果等差数列涉及到两个区间的部分时,我们是不知道较后的那个区间的首项,那么此时我们应该算出该区间的首项,即(前区间的长度*d+k),将其保存。最后当我们遇到多个lazy重叠时,我们不用下放,直接加上去就行。
注意可能会有首项或公差为0的情况,记得加上这种情况。
#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[100001];
struct node
{
int l,r,lc,rc,sum;
int lazy,gc;
};
int len=0;
node e[500000];
int ins(int x,int y)
{
len++;
int now=len;
int l=x,r=y,lc=-1,rc=-1,sum=0;
if(x==y) sum=a[x];
else
{
int mid=(l+r)/2;
lc=ins(l,mid);
rc=ins(mid+1,r);
}
e[now]={l,r,lc,rc,sum,0,0};
return now;
}
void down(int now)
{
int l=e[now].l,r=e[now].r;
if(l==r)
{
e[now].sum+=e[now].lazy;
e[now].lazy=0;
e[now].gc=0;
return ;
}
else
{
int lc=e[now].lc,rc=e[now].rc;
int mid=(l+r)/2;
e[lc].lazy+=e[now].lazy;
e[lc].gc+=e[now].gc;
e[rc].lazy+=e[now].lazy+e[now].gc*(mid-l+1);
e[rc].gc+=e[now].gc;
e[now].lazy=0;
e[now].gc=0;
return ;
}
}
void cg(int now,int x,int y,int k,int gc)
{
int l=e[now].l,r=e[now].r;
if(x==l&&y==r)
{
e[now].lazy+=k;
e[now].gc+=gc;
return ;
}
else
{
if(e[now].lazy!=0||e[now].gc!=0) down(now);
int lc=e[now].lc,rc=e[now].rc;
int mid=(l+r)/2;
if(x>=mid+1) cg(rc,x,y,k,gc);
else if(y<=mid) cg(lc,x,y,k,gc);
else
{
cg(lc,x,mid,k,gc);
cg(rc,mid+1,y,k+gc*(mid-x+1),gc);
}
}
}
int find(int now,int x)
{
int l=e[now].l,r=e[now].r;
if(e[now].lazy!=0||e[now].gc!=0) down(now);
if(l==x&&r==x) return e[now].sum;
else
{
int lc=e[now].lc,rc=e[now].rc;
int mid=(l+r)/2;
if(x>=mid+1) return find(rc,x);
else return find(lc,x);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
int root=ins(1,n);
for(int i=1;i<=m;i++)
{
int p;
scanf("%d",&p);
if(p==1)
{
int x,y,q,k;
scanf("%d%d%d%d",&x,&y,&q,&k);
cg(root,x,y,q,k);
}
else
{
int x;
scanf("%d",&x);
// if(x==261) printf("3250\n");
// else
printf("%d\n",find(root,x));
}
}
return 0;
}