Codeforces Round #546 (Div. 2) E. Nastya Hasn't Written a Legend(线段树+二分+数学转换)

题目链接:http://codeforces.com/contest/1136/problem/E

题目大意

给定两个序列,支持两种操作,
查询第一个序列的区间和,
第二种是修改a数组x位置上的值,增加x,
并且如果a[i+1]<a[i]+k[i] 那么a[i+1]=a[i]+k[i]。

题目分析 

[i+1]-S[i]<a[i]-S[i-1],这样我们把a[i]+S[i-1]整体看成一项
用线段树进行维护,然后求出来的和加上k数组的前缀和的前缀和区间和即可,
下面主要是如何维护题目要求:
对于第二种操作,我们要找到序列中第一个位置其大小不小于修改过后的值,
那么,我们不难想到用线段树二分,所以额外维护个最大值,当然懒惰标记数组
还是只需要一个,对于修改的区间:和变成(r-l+1)*v,最大值变成v,
那么我们有了最大值数组就可以二分了,如果左半区间最大值小于等于特定值,则
搜右半区间,否则,搜左半区间,这个很好想。
还有一个注意点就是数值有负数,lazy数组初始化为负无穷。

#include<bits/stdc++.h>
using namespace std;

#define debug puts("YES");
#define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++)
#define ll long long

#define lrt int l,int r,int rt
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define root l,r,rt
#define mst(a,b) memset((a),(b),sizeof(a))
#define pii pair<int,int>
#define fi first
#define se second
#define mk(x,y) make_pair(x,y)
const int mod=1e9+7;
const int maxn=1e5+5;
const int ub=1e6;
const ll INF=-1e18;
ll powmod(ll x,ll y){ll t; for(t=1;y;y>>=1,x=x*x%mod) if(y&1) t=t*x%mod; return t;}
ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
/*
题目大意:
给定两个序列,支持两种操作,
查询第一个序列的区间和,
第二种是修改a数组x位置上的值,增加x,
并且如果a[i+1]<a[i]+k[i] 那么a[i+1]=a[i]+k[i]。

题目分析:
这道题的关键是在数学转化上,上述关系式可以进一步写成:
a[i+1]-S[i]<a[i]-S[i-1],这样我们把a[i]+S[i-1]整体看成一项
用线段树进行维护,然后求出来的和加上k数组的前缀和的前缀和区间和即可,
下面主要是如何维护题目要求:
对于第二种操作,我们要找到序列中第一个位置其大小不小于修改过后的值,
那么,我们不难想到用线段树二分,所以额外维护个最大值,当然懒惰标记数组
还是只需要一个,对于修改的区间:和变成(r-l+1)*v,最大值变成v,
那么我们有了最大值数组就可以二分了,如果左半区间最大值小于等于特定值,则
搜右半区间,否则,搜左半区间,这个很好想。
还有一个注意点就是数值有负数,lazy数组初始化为负无穷。
*/
ll a[maxn],k[maxn],n,q;
int x,y;
int root[maxn<<2];
ll sum[maxn<<2],maxv[maxn<<2],lazy[maxn<<2];
void build(lrt){
    lazy[rt]=INF;
    if(l==r){
        maxv[rt]=sum[rt]=a[l];
        return ;
    }
    int mid=l+r>>1;
    build(lson),build(rson);
    maxv[rt]=max(maxv[rt<<1],maxv[rt<<1|1]);
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void pushdown(int rt,int l,int r,int mid){
    if(lazy[rt]!=INF){
        sum[rt<<1]=1LL*(mid-l+1)*lazy[rt];
        sum[rt<<1|1]=1LL*(r-mid)*lazy[rt];
        maxv[rt<<1]=lazy[rt];
        maxv[rt<<1|1]=lazy[rt];
        lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
        lazy[rt]=INF;
    }
}
void update(int l,int r,int rt,int L,int R,ll v){
    if(L>R) return ;
    if(L<=l&&r<=R){
        sum[rt]=1LL*(r-l+1)*v;
        maxv[rt]=lazy[rt]=v;
        return ;
    }
    int mid=l+r>>1;
    pushdown(rt,l,r,mid);
    if(L<=mid) update(l,mid,rt<<1,L,R,v);
    if(mid<R) update(mid+1,r,rt<<1|1,L,R,v);
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    maxv[rt]=max(maxv[rt<<1],maxv[rt<<1|1]);
    return ;
}
ll query1(int l,int r,int rt,int L,int R){
    if(L<=l&&r<=R) return sum[rt];
    int mid=l+r>>1;
    pushdown(rt,l,r,mid);
    ll ret=0;
    if(L<=mid) ret+=query1(l,mid,rt<<1,L,R);
    if(mid<R) ret+=query1(mid+1,r,rt<<1|1,L,R);
    return ret;
}
ll query2(int l,int r,int rt,int L,int R){
    if(L<=l&&r<=R) return maxv[rt];
    int mid=l+r>>1;
    pushdown(rt,l,r,mid);
    ll ret=-mod;
    if(L<=mid) ret=max(ret,query2(l,mid,rt<<1,L,R));
    if(mid<R) ret=max(ret,query2(mid+1,r,rt<<1|1,L,R));
    return ret;
}
int main(){
    mst(k,0),mst(a,0);
    cin>>n;
    rep(i,1,n+1) cin>>a[i];
    rep(i,1,n) cin>>k[i],k[i]+=k[i-1];
    rep(i,1,n+1) a[i]-=k[i-1];
    rep(i,1,n) k[i]+=k[i-1];
    build(1,n,1);///
    cin>>q;
    string op;
    while(q--){
        cin>>op;
        if(op[0]=='s'){
            cin>>x>>y;
            cout<<query1(1,n,1,x,y)+k[y-1]-k[max(0,x-2)]<<endl;
        }else{
            cin>>x>>y;
            ll v=query1(1,n,1,x,x)+y;
            int l=x,r=n,ans=r;
            while(l<=r){
                int mid=l+r>>1;
                if(query2(1,n,1,x,mid)<=v) ans=mid,l=mid+1;
                else r=mid-1;
            }
            update(1,n,1,x,ans,v);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37451344/article/details/88704498