• [uoj164][清华集训2015]V——线段树


    题目大意:

    传送门

    思路:

    对于这么多的操作,以及询问时的取历史最大值,用一般的线段树显然不太好做。
    于是考虑把每个操作转化成(h_i=max(h_i+a,b))的形式,不难发现第一种和第二种就是(h_i=max(h_i+x,0)),第三种即(h_i=max(h_i-inf,x))
    于是我们在线段树上对于每一个节点维护这两个标记,考虑如何合并标记:

    [egin{aligned} x &=max(max(x+a,b)+a',b')\ & =max(max(x+a+a',b+a'),b')\ & =max(x+a+a',max(b+a',b'))\ end{aligned}]

    这里假设(a,b)是原来的标记,(a',b')是新加上的标记。
    考虑如何求历史的最大值,对于一个点的最大值(max(x+a,b)),要么在左边取到,要么在右边取到,我们只需要记录左边的最大值和右边的最大值即可,即记录(ma=max a,mb=max b)
    同时(ma,mb)也是需要合并的,具体的式子自己推导一下就好了。

    #include<bits/stdc++.h>
    
    #define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
    #define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
    #define debug(x) cout<<#x<<"="<<x<<" "
    #define fi first
    #define se second
    #define mk make_pair
    #define pb push_back
    typedef long long ll;
    
    using namespace std;
    
    void File(){
    	freopen("uoj164.in","r",stdin);
    	freopen("uoj164.out","w",stdout);
    }
    
    template<typename T>void read(T &_){
    	_=0; T f=1; char c=getchar();
    	for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
    	for(;isdigit(c);c=getchar())_=(_<<1)+(_<<3)+(c^'0');
    	_*=f;
    }
    template<typename T>void chkmax(T &_,T __){_= __>_ ? __ : _;}
    
    const int maxn=5e5+10;
    const ll inf=1e18;
    int n,m;
    ll w[maxn];
    
    struct seg{
    	ll a,b,ma,mb;
    	void down(seg t){
    		ma=max(ma,a+t.ma); mb=max(mb,max(b+t.ma,t.mb));
    		a=max(a+t.a,-inf); b=max(b+t.a,t.b);
    	}
    	void reset(){a=b=ma=mb=0;}
    }c[maxn<<2];
    
    struct Segment_Tree{
    #define mid ((l+r)>>1)
    #define lc (o<<1)
    #define rc (o<<1|1)
    #define lson lc,l,mid
    #define rson rc,mid+1,r
    	void build(int o,int l,int r){
    		if(l==r)c[o]=(seg){w[l],0,w[l],0};
    		else build(lson),build(rson);
    	}
    	void update(int o,int l,int r,int L,int R,seg x){
    		if(L<=l && r<=R)c[o].down(x);
    		else{
    			c[lc].down(c[o]); c[rc].down(c[o]);
    			c[o].reset();
    			if(L<=mid)update(lson,L,R,x);
    			if(R>=mid+1)update(rson,L,R,x);
    		}
    	}
    	ll query(int o,int l,int r,int p,int ty){
    		if(l==r){
    			if(!ty)return max(c[o].a,c[o].b);
    			return max(c[o].ma,c[o].mb);
    		}
    		else{
    			c[lc].down(c[o]); c[rc].down(c[o]);
    			c[o].reset();
    			if(p<=mid)return query(lson,p,ty);
    			else return query(rson,p,ty);
    		}
    	}
    }T;
    
    int main(){
    	File();
    	read(n),read(m);
    	REP(i,1,n)read(w[i]);
    	T.build(1,1,n);
    	int ty,l,r;
    	ll x;
    	REP(i,1,m){
    		read(ty);
    		if(ty<=3){
    			read(l),read(r),read(x);
    			if(ty==1)T.update(1,1,n,l,r,(seg){x,0,x,0});
    			if(ty==2)T.update(1,1,n,l,r,(seg){-x,0,-x,0});
    			if(ty==3)T.update(1,1,n,l,r,(seg){-inf,x,-inf,x});
    		}
    		else{
    			read(l);
    			printf("%lld
    ",T.query(1,1,n,l,ty-4));
    		}
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    如何在 Linux 上用 IP转发使内部网络连接到互联网
    python 基础-文件读写'r' 和 'rb'区别
    处理HTTP状态码
    国内可用免费语料库(已经整理过,凡没有标注不可用的链接均可用)
    java读取大文件
    struts.properties的参数描述
    ResourceBundle使用
    linux定时任务的设置
    杂记
    JAVA动态加载JAR包的实现
  • 原文地址:https://www.cnblogs.com/ylsoi/p/10215859.html
Copyright © 2020-2023  润新知