Nastya Hasn't Written a Legend

传送门

题目:

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
  • 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为左端点在到最右边满足条件的右端点,这一区间都需要被修改,然后对于每次查询的区间合都可以用线段树实现,那么现在的问题就是如何确定右边界?

Nastya Hasn't Written a Legend_第1张图片

则只需要二分查找右端点就可以了,最后用线段数维护;

AC代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#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);
    }*/
}

 

你可能感兴趣的:(ACM)