UOJ #164. 【清华集训2015】V

该博客介绍了UOJ的一道题目,涉及区间赋值、区间加减、区间和的最大值等操作。通过使用一种标记表示法来简化问题,将区间修改转化为单点的max操作,并讨论了如何合并和查询这些标记以解决单点历史最大值的询问。博主分享了实现这些操作的AC代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

(居然)比想象中好写多了
操作:
区间赋值,区间加,区间减,区间和 0 0 0 m a x max max,单点询问,单点求历史最大值。
此题所有的修改都可以用一个标记表达:
( a , b ) (a,b) (a,b)表示将 x x x变为 m a x ( a + x , b ) max(a+x,b) max(a+x,b)
那么标记的合并可以发现 ( a , b ) ∗ ( c , d ) = ( a + c , m a x ( b + c , d ) ) (a,b)*(c,d)=(a+c,max(b+c,d)) (a,b)(c,d)=(a+c,max(b+c,d))
发现历史最大值标记也是形如 m a x ( a + x , b ) max(a+x,b) max(a+x,b)的形式。
这时标记需要合并与取 m a x max max

A C   C o d e \mathrm{AC \ Code} AC Code

#include<bits/stdc++.h>
#define maxn 500005
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define lc u<<1
#define rc u<<1|1
#define LL long long
#define Ct const
#define inf ((LL)1e16)
using namespace std;

char cb[1<<16],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<16,stdin),cs==ct)?0:*cs++)
void read(int &res){
	char ch;
	for(;!isdigit(ch=getc()););
	for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0');
}

int n,m,a[maxn];
struct data{
	LL ad,mx;
	data(LL ad=0,LL mx=0):ad(ad),mx(mx){}
	data operator *(Ct data &B)Ct{ return data(max(ad+B.ad,-inf),max(mx+B.ad,B.mx)); }
	data operator +(Ct data &B)Ct{ return data(max(ad,B.ad),max(mx,B.mx)); }
	LL cal(){ return max(ad,mx); }
}v1[maxn<<2],vp[maxn<<2];
void dtp(int u,Ct data &A,Ct data &B){
	vp[u] = vp[u] + v1[u] * B;
	v1[u] = v1[u] * A;
}
void dt(int u){
	if(v1[u].ad||v1[u].mx||vp[u].ad||vp[u].mx){
		dtp(lc,v1[u],vp[u]);
		dtp(rc,v1[u],vp[u]);
		v1[u]=vp[u]=data(0,0);
	}
}
void Build(int u,int l,int r){
	if(l==r) return (void)(v1[u]=vp[u]=data(a[l],0));
	int m=l+r>>1;Build(lc,l,m),Build(rc,m+1,r);
}
void add(int u,int l,int r,int ql,int qr,Ct data &A){
	if(l>qr||ql>r) return;
	if(ql<=l&&r<=qr) return (void)(dtp(u,A,A));
	int m=l+r>>1;dt(u),add(lc,l,m,ql,qr,A),add(rc,m+1,r,ql,qr,A);
}
void qry(int u,int l,int r,int p,int t){
	if(l==r) return (void)(printf("%lld\n",t?vp[u].cal():v1[u].cal()));
	int m=l+r>>1;dt(u),p<=m?qry(lc,l,m,p,t):qry(rc,m+1,r,p,t);
}

int main(){
	#if not ONLINE_JUDGE
	freopen("1.in","r",stdin);
	#endif
	read(n),read(m);
	rep(i,1,n) read(a[i]);
	Build(1,1,n);
	for(int op,l,r,x;m--;){
		read(op),read(l);
		if(op <= 3){
			read(r),read(x);
			if(op == 1) add(1,1,n,l,r,data(x,0));
			else if(op == 2) add(1,1,n,l,r,data(-x,0)); 
			else add(1,1,n,l,r,data(-inf,x));
		}
		else if(op == 4) qry(1,1,n,l,0);
		else qry(1,1,n,l,1);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值