• BZOJ 5117: [清华集训2015]V 线段树维护历史最值


    和 cpu 监控用的是一种做法. 

    令 $(a,b)$ 表示加上 a,再与 $b$ 取 max.  

    则 $(a,b)$ 与 $(c,d)$ 的历史最值合并可以看作是两个函数的合并,只需在 $(a,c)$ 中取一个 max,$(b,d)$ 中也取一个 max 即可.     

    仔细考虑一下标记的时间顺序:如果使用取 max,那么就没必要使用加法,如果使用加法,就没必要使用取 max.  

    所以说,这两者是互相独立的.       

    所以,我们维护取 max 的最大值与加法的最大值,就可以了.           

    code:   

    #include <cstdio> 
    #include <algorithm> 
    #include <cstring>    
    #define N 500006   
    #define lson x<<1  
    #define rson x<<1|1         
    #define ll long long 
    #define I(s) freopen(s".in","r",stdin) 
    #define O(s) freopen(s".out","w",stdout)   
    #define setIO(s) I(s)//,O(s) 
    using namespace std;             
    int n; 
    const ll inf=1ll<<60;    
    struct data 
    {      
        ll x,y;  
        data(ll a=0,ll b=-inf) { x=a,y=b; }         
        data operator+(const data &a)const { return data(max(-inf,x+a.x),max(y+a.x,a.y)); }   
        data operator*(const data &a)const { return data(max(x,a.x),max(y,a.y)); }        
    }ptag[N<<2],ntag[N<<2];                      
    ll pmax[N<<2],nmax[N<<2];             
    void pushup(int x) 
    {
        pmax[x]=max(pmax[lson],pmax[rson]);  
        nmax[x]=max(nmax[lson],nmax[rson]);  
    }    
    void build(int l,int r,int x) 
    {
        ptag[x]=ntag[x]=data();    
        if(l==r) 
        {   
            scanf("%lld",&nmax[x]),pmax[x]=nmax[x]; 
            return;   
        } 
        int mid=(l+r)>>1;   
        build(l,mid,lson),build(mid+1,r,rson);   
        pushup(x);  
    }   
    //  对于历史最大值           
    void mark_n(int x,data v) 
    {
        ntag[x]=ntag[x]+v;     
        nmax[x]=max(nmax[x]+v.x,v.y);        
    }
    void mark_p(int x,data v) 
    {           
        ptag[x]=ptag[x]*(ntag[x]+v);      
        pmax[x]=max(pmax[x],max(nmax[x]+v.x,v.y));       
    }       
    void pushdown(int x) 
    { 
        mark_p(lson,ptag[x]); 
        mark_n(lson,ntag[x]);      
        mark_p(rson,ptag[x]);        
        mark_n(rson,ntag[x]);
        ntag[x]=ptag[x]=data();    
    }
    void update(int l,int r,int x,int L,int R,data v) 
    {  
        if(l>=L&&r<=R) 
        {          
            mark_p(x,v); 
            mark_n(x,v);   
            return; 
        }  
        pushdown(x); 
        int mid=(l+r)>>1;     
        if(L<=mid) update(l,mid,lson,L,R,v); 
        if(R>mid)  update(mid+1,r,rson,L,R,v);   
        pushup(x); 
    }  
    ll query(int l,int r,int x,int L,int R,int o) 
    {
        if(l>=L&&r<=R) return o?nmax[x]:pmax[x];     
        pushdown(x); 
        int mid=(l+r)>>1;  
        ll re=-inf;      
        if(L<=mid)  re=max(re,query(l,mid,lson,L,R,o));  
        if(R>mid)   re=max(re,query(mid+1,r,rson,L,R,o)); 
        return re;  
    }
    int main() 
    { 
        // setIO("input");    
        int m; 
        scanf("%d%d",&n,&m);         
        build(1,n,1);        
        for(int i=1;i<=m;++i) 
        {       
            ll x; 
            int op,l,r;  
            scanf("%d",&op);  
            if(op==1) scanf("%d%d%lld",&l,&r,&x),update(1,n,1,l,r,data(x,-inf));    
            if(op==2) scanf("%d%d%lld",&l,&r,&x),update(1,n,1,l,r,data(-x,0));     
            if(op==3) scanf("%d%d%lld",&l,&r,&x),update(1,n,1,l,r,data(-inf,x));     
            if(op==4) scanf("%d",&l),printf("%lld
    ",query(1,n,1,l,l,1));    
            if(op==5) scanf("%d",&l),printf("%lld
    ",query(1,n,1,l,l,0));   
        }
        return 0; 
    }
    

      

  • 相关阅读:
    hadoop测试题目每天5题,总35题,第一天
    hadoop测试题目每天5题,总35题,第四天
    hadoop测试题目每天5题,总35题,第五天
    SP_EXECUTESQL 的用法
    元数据函数的使用 快速定位数据相关过程,表,函数
    javascript 層的拖動
    如何求得一个月的最后一个工作日
    利用ASP.NET实现分页管理器(高级篇)轉
    Asp.Net页面输出到EXCEL
    .net相关专题汇总
  • 原文地址:https://www.cnblogs.com/guangheli/p/12561526.html
Copyright © 2020-2023  润新知