uoj164【清华集训2015】V

博客介绍了【清华集训2015】V题目的链接及解题思路。该问题涉及五种操作:区间加法、区间减法、区间覆盖、单点询问和单点历史最大值。通过巧妙地使用pair来标记,将加法、减法和覆盖操作统一表示,并解释了如何合并不同标记以及进行单点询问和历史最大值查询的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接#164. 【清华集训2015】V
大佬的博客jefflyy
这个东西,,,诡异的标记下传。
一共有五种操作,区间加法,区间减法(减到0就不减了),区间覆盖,单点询问,单点历史最大值。
非常巧妙的使用了一个pair来进行标记。y=max(x+a,b)。
就是可以看做建立一个直角坐标系,其中x轴表示原数字,y轴表示修改后的数字,那么加法可以看做是 y = m a x ( x + a , 0 ) y=max(x+a,0) y=max(x+a,0),减法可以看做为 y = m a x ( x − a , 0 ) y=max(x-a,0) y=max(xa,0),覆盖则为 y = a 或 者 y = m a x ( − o o , a ) y=a或者y=max(-oo,a) y=ay=max(oo,a),故可以将这三种标记统一成 ( x + a , b ) (x+a,b) (x+a,b)的形式。
那么假设原来的标记是 ( a 1 , b 1 ) (a_1,b_1) (a1,b1),这是来了一个 ( a 2 , b 2 ) (a_2,b_2) (a2,b2)的标记,那么可以合并为: ( a 1 + a 2 , m a x ( b 1 + a 2 , b 2 ) ) (a_1+a_2,max(b_1+a_2,b_2)) (a1+a2,max(b1+a2,b2))
那么单点询问就是 m a x ( x + a , b ) max(x+a,b) max(x+a,b)了。
历史最大值的话,我们只需要记录历史中出现过的最大标记即可。

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

typedef long long ll;


const int maxn=5e5+7;

const ll inf=1e18;
int a[maxn<<2|1];

pair<ll,ll> p[maxn<<2|1];//max(x+a,x=b);
pair<ll,ll> maxx[maxn<<2|1];

void build(int l,int r,int k){
    p[k].first=maxx[k].first=0;
    p[k].second=maxx[k].second=-inf;
    if(l==r){
        scanf("%d",&a[l]);
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,k<<1);
    build(mid+1,r,k<<1|1);
}

void pushdown(int l,int r,int k){
    if(p[k].first||p[k].second!=-inf){

        maxx[k<<1].first=max(maxx[k<<1].first,maxx[k].first+p[k<<1].first);
        maxx[k<<1].second=max(maxx[k<<1].second,max(maxx[k].first+p[k<<1].second,maxx[k].second));

        maxx[k<<1|1].first=max(maxx[k<<1|1].first,maxx[k].first+p[k<<1|1].first);
        maxx[k<<1|1].second=max(maxx[k<<1|1].second,max(maxx[k].first+p[k<<1|1].second,maxx[k].second));

        p[k<<1].first=max(p[k<<1].first+p[k].first,-inf);
        p[k<<1].second=max(p[k<<1].second+p[k].first,p[k].second);

        p[k<<1|1].first=max(p[k<<1|1].first+p[k].first,-inf);
        p[k<<1|1].second=max(p[k<<1|1].second+p[k].first,p[k].second);

        p[k].first=maxx[k].first=0;
        p[k].second=maxx[k].second=-inf;
    }
}

void updata(int l,int r,int k,int L,int R,ll a,ll b){
    if(l>=L&&r<=R){
        p[k].first=max(p[k].first+a,-inf);
        p[k].second=max(p[k].second+a,b);
        maxx[k].first=max(maxx[k].first,p[k].first);
        maxx[k].second=max(maxx[k].second,p[k].second);
        return ;
    }
    pushdown(l,r,k);
    int mid=(l+r)>>1;
    if(L<=mid) updata(l,mid,k<<1,L,R,a,b);
    if(R>mid) updata(mid+1,r,k<<1|1,L,R,a,b);
}

ll myfindid(int l,int r,int k,int id){
    if(l==r) return max(a[l]+p[k].first,p[k].second);
    pushdown(l,r,k);
    int mid=(l+r)>>1;
    if(id<=mid) return myfindid(l,mid,k<<1,id);
    return myfindid(mid+1,r,k<<1|1,id);
}

ll myfindmax(int l,int r,int k,int id){
    if(l==r) return max(a[l]+maxx[k].first,maxx[k].second);
    pushdown(l,r,k);
    int mid=(l+r)>>1;
    if(id<=mid) return myfindmax(l,mid,k<<1,id);
    return myfindmax(mid+1,r,k<<1|1,id);
}

int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    build(1,n,1);
    int id,l,r,x;
    while(m--){
        scanf("%d",&id);
        if(id==1){
            scanf("%d%d%d",&l,&r,&x);
            updata(1,n,1,l,r,x,0);
        }
        else if(id==2){
            scanf("%d%d%d",&l,&r,&x);
            updata(1,n,1,l,r,-x,0);
        }
        else if(id==3){
            scanf("%d%d%d",&l,&r,&x);
            updata(1,n,1,l,r,-inf,x);
        }
        else if(id==4){
            scanf("%d",&l);
            printf("%lld\n",myfindid(1,n,1,l));
        }
        else{
            scanf("%d",&l);
            printf("%lld\n",myfindmax(1,n,1,l));
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值