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\n",max(za,zb));
		}
	}
	return 0;
}

转载于:https://www.cnblogs.com/lcf-2000/p/6579097.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值