Codeforces Round #546 (Div. 2)E. Nastya Hasn't Written a Legend(二分+线段树(区间赋值))

E. Nastya Hasn’t Written a Legend

题意:

输入 n ( 1 e 5 ) n(1e5) n(1e5)
第二行输入 a 1 , a 2 , … , a n ( − 1 e 9 − 1 e 9 ) a_1,a_2,\dots,a_n(-1e9-1e9) a1,a2,,an(1e91e9)
第三行输入 k 1 , k 2 , … , k n − 1 ( − 1 e 9 − 1 e 9 ) k_1,k_2,\dots,k_{n-1}(-1e9-1e9) k1,k2,,kn1(1e91e9)
输入保证 a i + k i ≤ a i + 1 ( 1 ≤ i ≤ n − 1 ) a_i+k_i\leq a_{i+1}(1\leq i\leq n-1) ai+kiai+1(1in1)
输入 q ( 1 e 5 ) q(1e5) q(1e5)接下来 q q q行:
+ , i , x +,i ,x +,i,x表示操作 a i + = x a_i+=x ai+=x,在操作过程中若有 a j + k j > a [ j + 1 ] ( 1 ≤ j ≤ n − 1 ) a_j+k_j>a[j+1](1\leq j\leq n-1) aj+kj>a[j+1](1jn1),那么 a j + 1 = a j + k j a_{j+1}=a_j+k_j aj+1=aj+kj
s , l , r s,l,r s,l,r表示询问 a l + a l + 1 + ⋯ + a r a_l+a_{l+1}+\dots+a_r al+al+1++ar

题解:

首先分析这个序列具有单调的性质;不妨设:
a 1 = a 1 + x 1 , a 2 = a 1 + k 1 + x 2 , a 3 = a 1 + k 1 + k 2 + x 3 , … , a n = a 1 + k 1 + k 2 + ⋯ + k n − 1 + x n ( 0 = x 1 ≤ x 2 ≤ x 3 ≤ ⋯ ≤ x n ) a_1=a_1+x_1,a_2=a_1+k_1+x_2,a_3=a_1+k_1+k_2+x_3,\dots,a_n=a_1+k_1+k_2+\dots+k_{n-1}+x_n(0=x_1\leq x_2\leq x_3\leq\dots\leq x_n) a1=a1+x1,a2=a1+k1+x2,a3=a1+k1+k2+x3,,an=a1+k1+k2++kn1+xn(0=x1x2x3xn)
只要保证 ( x 1 ≤ x 2 ≤ x 3 ≤ ⋯ ≤ x n ) (x_1\leq x_2\leq x_3\leq\dots\leq x_n) (x1x2x3xn)即可;当 x i > x i + 1 x_i>x_{i+1} xi>xi+1时,使 x i + 1 = x i x_{i+1}=x_{i} xi+1=xi即可。因此用线段树维护 X X X数组就好。
a i + = x a_i+=x ai+=x时,即 x i + = x x_i+=x xi+=x,二分找到最右边的 j j j,使 x j ≤ x i x_j\leq x_i xjxi,并将 x i , x i + 1 , … , x j x_i,x_{i+1},\dots,x_j xi,xi+1,,xj全赋为 x i x_i xi,即可。
最后就查询区间和,就不用说了吧。

代码:

#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
//#define int long long
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+9;
#define ll long long
ll n,a[N],sum[N],ssum[N];
ll he[N<<2],tag[N<<2];
void push_down(int p,int l,int r){
    if(tag[p]){
        int mid=(l+r)>>1;
        tag[ls(p)]=tag[rs(p)]=tag[p];
        he[ls(p)]=(mid-l+1)*tag[p],he[rs(p)]=(r-mid)*tag[p];
        tag[p]=0;
    }
}
void push_up(int p){he[p]=he[ls(p)]+he[rs(p)];}
void update(int p,int l,int r,int ql,int qr,ll qz){
    if(ql<=l&&r<=qr){
        tag[p]=qz;
        he[p]=1ll*(r-l+1)*qz;
        return;
    }
    push_down(p,l,r);
    int mid=(l+r)>>1;
    if(ql<=mid)update(ls(p),l,mid,ql,qr,qz);
    if(qr>mid)update(rs(p),mid+1,r,ql,qr,qz);
    push_up(p);
}
ll query(int p,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr)return he[p];
    push_down(p,l,r);
    int mid=(l+r)>>1;ll ans=0;
    if(ql<=mid)ans+=query(ls(p),l,mid,ql,qr);
    if(qr>mid)ans+=query(rs(p),mid+1,r,ql,qr);
    return ans;
}
signed main(){
   // freopen("tt.in","r",stdin),freopen("tt.out","w",stdout);
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<n;i++){int t;cin>>t;sum[i]=sum[i-1]+t;}
    for(int i=1;i<=n;i++)ssum[i]=ssum[i-1]+a[1]+sum[i-1];
    for(int i=1;i<=n;i++)update(1,1,n,i,i,a[i]-a[1]-sum[i-1]);//cout<<a[i]-a[1]-sum[i-1]<<" ";cout<<endl;
    int q;
    cin>>q;
    char c;int l,r;
    while(q--){
        cin>>c>>l>>r;
        if(c=='+'){
            ll now=query(1,1,n,l,l);
		//	cout<<now<<endl;
            now+=r;
		//	cout<<l<<" "<<r<<" "<<now<<endl;
            int L=l,R=n,mid,ans;
            while(L<=R){
                mid=(L+R)>>1;
                if(query(1,1,n,mid,mid)<=now)ans=mid,L=mid+1;
                else R=mid-1;
            }
			//cout<<ans<<endl;
            update(1,1,n,l,ans,now);
        }else{
		//	cout<<"wen\n";
	//		cout<<l<<" "<<r<<" "<<query(1,1,n,l,r)<<" "<<ssum[r]-ssum[l-1]<<endl;
            cout<<query(1,1,n,l,r)+ssum[r]-ssum[l-1]<<endl;
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值