zoukankan      html  css  js  c++  java
  • UOJ #164 【清华集训2015】 V

    题目链接:V

      这道题由于是单点询问,所以异常好写。

      注意到每种修改操作都可以用一个标记((a,b))表示。标记((a,b))的意义就是(x= max{x+a,b}) 

      同时这种标记也是支持合并的。有((a,b)+(c,d)=(a+c,max{b+c,d}))

      用上这种标记的话,(1)操作就是((x,0)),(2)操作就是((-x,0)),(3)操作就是((-inf,x))。

      要查询单点值的话只要把所有标记都下放了就好了。

      这种标记也支持取(max)。即,(max{(a,b),(c,d)}=(max{a,c},max{b,d}))。本质上就是一个分段函数取(max)的过程。

      所以最后一问再维护一个历史最大值这道题就做完了。注意下传标记时先传历史标记。

      还有一个要注意的地方:标记((a,b))里的(a)实际上是(max{a,-inf})。注意修改的时候和(-inf)取个(max),不然很容易就爆掉了。

      下面贴代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
    #define max(a,b) (a>b?a:b)
    #define maxn 500010
    #define INF (1LL<<60)
    
    using namespace std;
    typedef long long llg;
    
    int n,m,L,R;
    llg na[maxn<<2],nb[maxn<<2];
    llg pa[maxn<<2],pb[maxn<<2],za,zb;
    
    int getint(){
    	int w=0;bool q=0;
    	char c=getchar();
    	while((c>'9'||c<'0')&&c!='-') c=getchar();
    	if(c=='-') c=getchar(),q=1;
    	while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar();
    	return q?-w:w;
    }
    
    void pushdown(int u){
    	for(int i=0,v;v=u<<1|i,i<2;i++){
    		pa[v]=max(pa[v],pa[u]+na[v]);
    		pb[v]=max(pb[v],max(pb[u],nb[v]+pa[u]));
    		na[v]=max(na[v]+na[u],-INF);
    		nb[v]=max(nb[v]+na[u],nb[u]);
    	}
    	na[u]=nb[u]=pa[u]=pb[u]=0;
    }
    
    void build(int u,int l,int r){
    	int lc=u<<1,lv=u<<1|1,mid=(l+r)>>1;
    	if(l==r) na[u]=pa[u]=getint();
    	else build(lc,l,mid),build(lv,mid+1,r);
    }
    
    void add(int u,int l,int r){
    	int lc=u<<1,lv=u<<1|1,mid=(l+r)>>1;
    	if(L<=l && r<=R){
    		na[u]=max(na[u]+za,-INF);
    		nb[u]=max(nb[u]+za,zb);
    		pa[u]=max(pa[u],na[u]);
    		pb[u]=max(pb[u],nb[u]);
    		return;
    	}
    	pushdown(u);
    	if(L<=mid) add(lc,l,mid);
    	if(R>mid) add(lv,mid+1,r);
    }
    
    void query(bool w){
    	int u=1,l=1,r=n,mid;
    	while(l!=r){
    		mid=(l+r)>>1;
    		pushdown(u); u<<=1;
    		if(L<=mid) r=mid;
    		else u|=1,l=mid+1;
    	}
    	za=w?na[u]:pa[u];
    	zb=w?nb[u]:pb[u];
    }
    
    int main(){
    	File("a");
    	n=getint(),m=getint();
    	build(1,1,n);
    	while(m--){
    		int ty=getint(),x;
    		if(ty<=3){
    			L=getint(),R=getint();x=getint();
    			if(ty==1) za=x,zb=0;
    			if(ty==2) za=-x,zb=0;
    			if(ty==3) za=-INF,zb=x;
    			add(1,1,n);
    		}
    		else{
    			L=R=getint(); query(ty==4);
    			printf("%lld
    ",max(za,zb));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    HDU 逃离迷宫 (bfs)
    HDU 2588 GCD (欧拉函数)
    HDU 诡异的楼梯 (bfs)
    oj 二叉树相关
    AVL树代码实现
    用栈实现队列
    redis学习
    15. 三数之和 (思维)
    889. 根据前序和后序遍历构造二叉树(非递归)
    寻找重复的子树(dfs)
  • 原文地址:https://www.cnblogs.com/lcf-2000/p/6579097.html
Copyright © 2011-2022 走看看