In this task, Nastya asked us to write a formal statement.
An array a of length n and an array k of length n−1 are given. Two types of queries should be processed:
increase ai by x. Then if ai+1<ai+ki, ai+1 becomes exactly ai+ki; again, if ai+2<ai+1+ki+1, ai+2 becomes exactly ai+1+ki+1, and so far for ai+3, …, an;
print the sum of the contiguous subarray from the l-th element to the r-th element of the array a.
It’s guaranteed that initially ai+ki≤ai+1 for all 1≤i≤n−1.
Input
The first line contains a single integer n (2≤n≤105) — the number of elements in the array a.
The second line contains n integers a1,a2,…,an (−109≤ai≤109) — the elements of the array a.
The third line contains n−1 integers k1,k2,…,kn−1 (−106≤ki≤106) — the elements of the array k.
The fourth line contains a single integer q (1≤q≤105) — the number of queries.
Each of the following q lines contains a query of one of two types:
if the query has the first type, the corresponding line contains the character ‘+’ (without quotes), and then there are two integers i and x (1≤i≤n, 0≤x≤106), it means that integer x is added to the i-th element of the array a as described in the statement.
if the query has the second type, the corresponding line contains the character ‘s’ (without quotes) and then there are two integers l and r (1≤l≤r≤n).
Output
For each query of the second type print a single integer in a new line — the sum of the corresponding subarray.
Examples
inputCopy
3
1 2 3
1 -1
5
s 2 3
- 1 2
s 1 2 - 3 1
s 2 3
outputCopy
5
7
8
inputCopy
3
3 6 7
3 1
3 - 1 3
- 2 4
s 1 3
outputCopy
33
Note
In the first example:
after the first change a=[3,4,3];
after the second change a=[3,4,4].
In the second example:
after the first change a=[6,9,10];
after the second change a=[6,13,14].
题意:
给你两个数组,第一个数组是n个值,第二个数组是改变量,什么叫改变量呢,当我增加第一个数组的x位置的值y的时候,如果a[x]+y+k[x]>a[x+1],那么a[x+1]=a[x]+y+k[x]。一直比到最后。还有一个操作是问你l到r区间值的和。一开始默认所有a[x]+k[x]<a[x+1]
题解:
非常好的题目,我想了很久都做不出来。当看到网上题解写二分的时候,茅厕顿开呀。因为到一个点a[x]>a[x-1]+前缀的时候,那么之后的就也无法更新,因为a[x]状态不变的话,后面状态是不会改变的,满足二分的性质,所以我们二分更新到哪里结束即可。之后就是怎么更新的问题,线段树维护的是区间和,那么对于更新某个位置x,我们知道a[x+1]=a[x]+y+k[x],a[x+2]=a[x]+y+k[x]+k[x+1]。这样的话我们用一个前缀和数组p来记录k的前缀和,之后,对于这个区间l到r,我们可以发现k[l]加了(r-l+1)次,k[l+1]加了(r-l)次,同样的,我们就可以用一个前缀和数组pp来表示p数组的前缀和,这样就能得到k[i]加了(n-i+1)次的和。那么我们更新的时候就是pp[r]-pp[l-1]+(a[x]+y)(r-l+1)-p[x]*(r-l+1);
因为pp[r]-pp[l-1]表示的是从l到r这个区间,从1~l,到1~r的前缀和的和,但是我们计算前缀和当然是要从x开始,所以我们要减掉(r-l+1)个1~x的前缀和,也就是-p[x](r-l+1)。但是我们怎么维护x?可能他会被push_down,如果用一个标记记录的话,下一次就不知道x到底是哪个位置了,但是我们发现a[x]+y与p[x]的系数都是一样的,所以我们在更新的时候直接合并a[x]+y-p[x],记为val,那么这个区间的和就是pp[r]-pp[l-1]+(r-l+1)*val。
最后一点要注意的是,延迟更新标记不能用+=,因为这道题特殊点在于它并不是+=,对于一个点如果两次都被更新,那么就以后一次更新为准。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+5;
const ll inf=1e18;
ll a[N],p[N],pp[N],sum[N*4],flag[N*4],k[N];
void build(int l,int r,int root)
{
flag[root]=-inf;
if(l==r)
{
sum[root]=a[l];
return ;
}
int mid=l+r>>1;
build(l,mid,root<<1);
build(mid+1,r,root<<1|1);
sum[root]=sum[root<<1]+sum[root<<1|1];
}
void push_down(ll l,ll r,int root)
{
if(flag[root]==-inf)
return ;
ll mid=l+r>>1;
sum[root<<1]=flag[root]*(mid-l+1)+pp[mid]-pp[l-1];
sum[root<<1|1]=flag[root]*(r-mid)+pp[r]-pp[mid];
flag[root<<1]=flag[root];
flag[root<<1|1]=flag[root];
flag[root]=-inf;
}
void update(ll l,ll r,ll root,ll ql,ll qr,ll val)
{
if(l>=ql&&r<=qr)
{
sum[root]=pp[r]-pp[l-1]+val*(r-l+1);
flag[root]=val;
return ;
}
push_down(l,r,root);
int mid=l+r>>1;
if(mid>=ql)
update(l,mid,root<<1,ql,qr,val);
if(mid<qr)
update(mid+1,r,root<<1|1,ql,qr,val);
sum[root]=sum[root<<1]+sum[root<<1|1];
}
ll query(int l,int r,int root,int ql,int qr)
{
if(l>=ql&&r<=qr)
return sum[root];
push_down(l,r,root);
int mid=l+r>>1;
ll ans=0;
if(mid>=ql)
ans=query(l,mid,root<<1,ql,qr);
if(mid<qr)
ans+=query(mid+1,r,root<<1|1,ql,qr);
return ans;
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
build(1,n,1);
for(int i=2;i<=n;i++)
scanf("%lld",&k[i]),p[i]=p[i-1]+k[i];
for(int i=2;i<=n;i++)
pp[i]=pp[i-1]+p[i];
int m;
scanf("%d",&m);
while(m--)
{
char op[2];
int x,y;
scanf("%s%d%d",op,&x,&y);
if(op[0]=='s')
printf("%lld\n",query(1,n,1,x,y));
else
{
int l=x,r=n,ans=l,mid;
ll aa=query(1,n,1,x,x);
while(r>=l)
{
mid=l+r>>1;
ll amid=query(1,n,1,mid,mid);
if(amid<aa+y+p[mid]-p[x])
l=mid+1,ans=mid;
else
r=mid-1;
}
update(1,n,1,x,ans,aa+y-p[x]);
}
}
return 0;
}