题目:
In this task, Nastya asked us to write a formal statement.
An array aa of length nn and an array kk of length n−1n−1 are given. Two types of queries should be processed:
- increase aiai by xx. Then if ai+1<ai+kiai+1<ai+ki, ai+1ai+1 becomes exactly ai+kiai+ki; again, if ai+2<ai+1+ki+1ai+2<ai+1+ki+1, ai+2ai+2 becomes exactly ai+1+ki+1ai+1+ki+1, and so far for ai+3ai+3, ..., anan;
- print the sum of the contiguous subarray from the ll-th element to the rr-th element of the array aa.
It's guaranteed that initially ai+ki≤ai+1ai+ki≤ai+1 for all 1≤i≤n−11≤i≤n−1.
Input
The first line contains a single integer nn (2≤n≤1052≤n≤105) — the number of elements in the array aa.
The second line contains nn integers a1,a2,…,ana1,a2,…,an (−109≤ai≤109−109≤ai≤109) — the elements of the array aa.
The third line contains n−1n−1 integers k1,k2,…,kn−1k1,k2,…,kn−1 (−106≤ki≤106−106≤ki≤106) — the elements of the array kk.
The fourth line contains a single integer qq (1≤q≤1051≤q≤105) — the number of queries.
Each of the following qq 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 ii and xx(1≤i≤n1≤i≤n, 0≤x≤1060≤x≤106), it means that integer xx is added to the ii-th element of the array aa 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 lland rr (1≤l≤r≤n1≤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
input
Copy
3 1 2 3 1 -1 5 s 2 3 + 1 2 s 1 2 + 3 1 s 2 3
output
Copy
5 7 8
input
Copy
3 3 6 7 3 1 3 + 1 3 + 2 4 s 1 3
output
Copy
33
Note
In the first example:
- after the first change a=[3,4,3]a=[3,4,3];
- after the second change a=[3,4,4]a=[3,4,4].
In the second example:
- after the first change a=[6,9,10]a=[6,9,10];
after the second change a=[6,13,14]a=[6,13,14];
题意:给你俩个数组-x和k数组,x数组初始满足x[i]+k[i]<=x[i+1],m次操作,每次操作有俩种,一种是在x数组中的第i个加上一个值y;另一种就是输出i到y区间的x数组的合,对于x数组如果满足x[i]+k[i]>x[i+1],x[i+1]就会被替换为x[i]+k[i];
题解:定义y数组为k的前n项和,sum数组为y数组的前n项和,对于每次修改当x[i]+k[i]>x[i+1],x[i+1]就会被替换为x[i]+k[i];则以i为左端点在到最右边满足条件的右端点,这一区间都需要被修改,然后对于每次查询的区间合都可以用线段树实现,那么现在的问题就是如何确定右边界?
则只需要二分查找右端点就可以了,最后用线段数维护;
AC代码:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
#include<vector>
#include<map>
#include<stdlib.h>
#include<math.h>
#define ll long long
using namespace std;
const int maxn=1e5+5;
const ll inf=9223372036854775807;
struct node{
ll lazy;
ll sum;
int l2;
};
node tree[maxn*4];
ll x[maxn],y[maxn],ans,sum[maxn];
ll get(int l,int r){
return sum[r]-sum[l]-y[l-1]*(r-l);
}
void build(int l,int r,int k){
tree[k].lazy=inf;
if(l==r){
tree[k].sum=x[l];
return ;
}
int mid=(l+r)>>1;
build(l,mid,2*k);
build(mid+1,r,2*k+1);
tree[k].sum=tree[2*k].sum+tree[2*k+1].sum;
}
void modify(int k,int l,int r){
int mid=(l+r)>>1;
int l1=tree[k].l2;
tree[2*k].lazy=tree[k].lazy;
tree[2*k].l2=tree[k].l2;
tree[2*k].sum=tree[2*k].lazy*(mid-l+1)+get(l1,mid);
if(l!=l1)
tree[2*k].sum-=get(l1,l-1);
tree[2*k+1].lazy=tree[k].lazy;
tree[2*k+1].l2=tree[k].l2;
tree[2*k+1].sum=tree[2*k+1].lazy*(r-mid)+get(l1,r)-get(l1,mid);
//printf("****%d %d %lld %d %lld %lld %lld %lld\n",mid+1,r,get(l1,mid),l1,get(l1,r),sum[r],sum[l1],y[l1]);
//printf("%d %lld\n",l1,y[l1]);
tree[k].lazy=inf;
}
void add(int l,int r,int l1,int r1,int k,ll len){
if(l>=l1&&r<=r1){
tree[k].lazy=len;
tree[k].sum=tree[k].lazy*(r-l+1)+get(l1,r);
if(l!=l1)
tree[k].sum-=get(l1,l-1);
tree[k].l2=l1;
//printf("%d %d %d %lld %lld %lld %lld\n",l,r,l1,len,tree[k].sum,get(l1,r),get(l1,l-1));
return ;
}
if(tree[k].lazy!=inf)
modify(k,l,r);
int mid=(l+r)>>1;
if(mid>=l1)
add(l,mid,l1,r1,2*k,len);
if(mid+1<=r1)
add(mid+1,r,l1,r1,2*k+1,len);
tree[k].sum=tree[2*k].sum+tree[2*k+1].sum;
}
void query(int l,int r,int l1,int r1,int k){
if(l>=l1&&r<=r1){
//printf("%d %d %lld\n",l,r,tree[k].sum);
ans+=tree[k].sum;
return ;
}
if(tree[k].lazy!=inf)
modify(k,l,r);
int mid=(l+r)>>1;
if(mid>=l1)
query(l,mid,l1,r1,2*k);
if(mid+1<=r1)
query(mid+1,r,l1,r1,2*k+1);
tree[k].sum=tree[2*k].sum+tree[2*k+1].sum;
}
int dichotomize(int n,int k){
int l=k,r=n;
int ans1=l;
while(r>=l){
int mid=(l+r)>>1;
ans=0;
query(1,n,mid,mid,1);
//printf("%lld %lld %lld %lld\n",x[k],y[mid]-y[k],ans);
if(x[k]+y[mid-1]-y[k-1]>ans){
l=mid+1;
ans1=mid;
}
else
r=mid-1;
}
return ans1;
}
int main( )
{
int n;
scanf("%d",&n);
for(int a=1;a<=n;a++)
scanf("%lld",&x[a]);
sum[1]=0;
y[0]=0;
for(int b=1;b<=n-1;b++){
ll i;
scanf("%lld",&i);
y[b]=i+y[b-1];
sum[b+1]=sum[b]+y[b];
}
/*for(int a=1;a<=n;a++)
printf("%d %lld %lld\n",a,sum[a],y[a]);*/
build(1,n,1);
int q;
scanf("%d",&q);
while(q--){
char z[2];
ll i,j;
scanf("%s %lld %lld",z,&i,&j);
if(z[0]=='+'){
ans=0;
query(1,n,i,i,1);
x[i]=ans+j;
//printf("%lld\n",x[i]);
int r=dichotomize(n,i);
//printf("%d %lld\n",r,x[i]);
add(1,n,i,r,1,x[i]);
}
else{
ans=0;
query(1,n,i,j,1);
printf("%lld\n",ans);
}
}
/*for(int a=1;a<=n;a++){
ans=0;
query(1,n,a,a,1);
printf("%lld\n",ans);
}*/
}