• uoj#164. 【清华集训2015】V


    传送门:http://uoj.ac/problem/164

    思路:科学的题面:

    请你写一个数据结构支持以下功能:

    1:区间[l,r]加x

    2:区间[l,r]减x并和0取max

    3:区间覆盖

    4:单点询问

    5:单点历史最大值询问


    线段树维护分段函数

    标记就是一个二元组(a,b)表示标记生效后x=max(x+a,b)

    1操作就是打(x,0)的标记

    2就是(-x,0)

    3就是(-inf,v)

    我们手推一下就可以发现这个标记是满足结合律和封闭性的

    然后两个标记怎么合并呢?

    g(f(x))=max(x+max(fa+ga,-inf),max(fb+ga,gb))(打f标记的时间在前,打g标记在后)

    中间和-inf取max是为了不使多个-inf加爆了


    对于历史最大值,我们要记录的是历史最大标记而不是直接在每个点记录历史最大值

    为什么是这样的?

    假设我们进行一次区间赋为inf的操作,接着有全部赋为0,标记还没来得及下传更新历史最大值就被后一个标记cha了

    所以每个点记录历史最大值是错的

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define PI pair<long long,long long>
    #define mp(a,b) make_pair(a,b)
    #define fi first
    #define se second
    typedef long long ll;
    const int maxn=500010;
    const ll inf=4557430888798830399ll;
    using namespace std;
    int n,m,a[maxn];
    PI max(PI a,PI b){return mp(max(a.fi,b.fi),max(a.se,b.se));}
    PI operator +(PI f,PI g){return mp(max(f.fi+g.fi,-inf),max(f.se+g.fi,g.se));}
    
    struct Tsegment{
    	#define ls (p<<1)
    	#define rs ((p<<1)|1)
    	#define mid ((l+r)>>1)
    	PI now[maxn<<2],ever[maxn<<2];
    	void add(int p,int ch){
    		ever[ch]=max(ever[ch],now[ch]+ever[p]);
    		now[ch]=now[ch]+now[p];
    	}
    	void down(int p){
    		add(p,ls),add(p,rs);
    		now[p]=ever[p]=mp(0,0);
    	}
    	void build(int p,int l,int r){
    		if (l==r){now[p]=ever[p]=mp(a[l],0);return;}
    		build(ls,l,mid),build(rs,mid+1,r);
    	}
    	void modify(int p,int l,int r,int a,int b,PI v){
    		//printf("p=%d l=%d r=%d a=%d b=%d
    ",p,l,r,a,b);
    		if (l==a&&r==b){
    			now[p]=now[p]+v;
    			ever[p]=max(ever[p],now[p]);
    			return;
    		}
    		down(p);
    		if (b<=mid) modify(ls,l,mid,a,b,v);
    		else if (a>mid) modify(rs,mid+1,r,a,b,v);
    		else modify(ls,l,mid,a,mid,v),modify(rs,mid+1,r,mid+1,b,v);
    	}
    	ll query(int p,int l,int r,int x,int op){
    		if (l==r){
    			if (op) return max(ever[p].fi,ever[p].se);
    			else return max(now[p].fi,now[p].se);
    		}
    		down(p);
    		if (x<=mid) return query(ls,l,mid,x,op);
    		else return query(rs,mid+1,r,x,op);
    	}
    	void cover(int l,int r,int v){modify(1,1,n,l,r,mp(-inf,v));}
    	void inc(int l,int r,int v){modify(1,1,n,l,r,mp(v,0));}
    	ll query(int x,int op){return query(1,1,n,x,op);}
    }T;
    
    int main(){
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    	T.build(1,1,n);
    	for (int i=1,l,r,x,op;i<=m;i++){
    		scanf("%d",&op);
    		if (op==1) scanf("%d%d%d",&l,&r,&x),T.inc(l,r,x);
    		else if (op==2) scanf("%d%d%d",&l,&r,&x),T.inc(l,r,-x);
    		else if (op==3) scanf("%d%d%d",&l,&r,&x),T.cover(l,r,x);
    		else if (op==4) scanf("%d",&x),printf("%lld
    ",T.query(x,0));
    		else if (op==5) scanf("%d",&x),printf("%lld
    ",T.query(x,1));
    		else if (op==6){
    			for (int i=1;i<=n;i++)
    				printf("%lld ",T.query(i,0));puts("");
    		}
    		else if (op==7){
    			for (int i=1;i<=n;i++)
    				printf("%lld ",T.query(i,1));puts("");
    		}
    	}
    	return 0;
    }
    /*
    5 6
    1 2 3 4 5
    
    2 1 3 2 //0 0 1 4 5
    4 1 //0
    1 1 4 1 //1 1 2 5 6
    5 3 //3
    3 1 5 4 //4 4 4 4 4
    4 2 //4
    
    
    
    */


  • 相关阅读:
    数组实现栈
    栈应用实例单词逆序
    使用JXMapViewer将地图集成到swing app中
    使用xbee连接地面站和飞控
    QWT编译、配置、使用(Qt Creator)
    Qt跨线程调用错误解析及解决办法
    SVN版本服务器搭建(服务端+客户端)
    opencv配置过程 (cmake,vs2013,qt 5.4)
    基数排序/Go实现
    c/c++ 编译器内存对齐问题
  • 原文地址:https://www.cnblogs.com/thythy/p/5493629.html
Copyright © 2020-2023  润新知