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

浅谈区间最值操作与历史最值问题:https://www.cnblogs.com/AKMer/p/10225100.html

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

论文题。论文做法如下:

首先我们定义一种标记\((a,b)\),表示给这个区间先加上\(a\)再跟\(b\)\(max\),不难发现题目里提到的三种操作分别都可以用这样的标记来代替:

1、区间加\(v\)\((v,-inf)\)

2、区间减\(v\)\((-v,0)\)

3、区间覆盖:\((-inf,v)\)

考虑合并两个标记\((a,b),(c,d)\),那么就会变成\((a+c,max(b+c,d))\)

现在考虑历史标记最大值,对于一个标记,我们可以将它看成是一个分段函数。第一段的函数是\(y=b\),第二段的函数是\(y=x+a\)。那么历史最大标记则可以用\((max(a,c),max(b,d))\)来表示。如下图,红色的部分就是历史标记最大值:

时间复杂度:\(O(nlogn)\)

空间复杂度:\(O(n)\)

代码如下:

#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;

const ll inf=1e18;
const int maxn=5e5+5;

int n,m;
int a[maxn];

int read() {
	int x=0,f=1;char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
	return x*f;
}

struct segment_tree {
	struct tag {
		ll add,mx;

		void init() {
			add=0,mx=-inf;
		}

		tag() {}

		tag(ll _add,ll _mx) {
			add=_add,mx=_mx;
		}

		tag operator+(const tag &a)const {
			return tag(max(-inf,add+a.add),max(mx+a.add,a.mx));
		}

		tag operator*(const tag &a)const {
			return tag(max(add,a.add),max(mx,a.mx));
		}
	};

	struct tree_node {
		ll hismx,mx;
		tag his,now;
	}tree[maxn<<2];

	void update(int p) {
		tree[p].mx=max(tree[p<<1].mx,tree[p<<1|1].mx);
		tree[p].hismx=max(tree[p<<1].hismx,tree[p<<1|1].hismx);
	}

	void build(int p,int l,int r) {
		tree[p].his.init(),tree[p].now.init();
		if(l==r) {tree[p].hismx=tree[p].mx=a[l];return;}
		int mid=(l+r)>>1;
		build(p<<1,l,mid),build(p<<1|1,mid+1,r);
		update(p);
	}

	void make_tag(int p,tag now,tag his) {
		tree[p].his=tree[p].his*(tree[p].now+his);
		tree[p].now=tree[p].now+now;
		ll res=max(tree[p].mx+his.add,his.mx);
		tree[p].hismx=max(tree[p].hismx,res);
		tree[p].mx=max(tree[p].mx+now.add,now.mx);
	}

	void push_down(int p) {
		make_tag(p<<1,tree[p].now,tree[p].his);
		make_tag(p<<1|1,tree[p].now,tree[p].his);
		tree[p].now.init(),tree[p].his.init();
	}

	void change(int p,int l,int r,int L,int R,ll v,ll mx) {
		if(L<=l&&r<=R) {make_tag(p,tag(v,mx),tag(v,mx));return;}
		int mid=(l+r)>>1;push_down(p);
		if(L<=mid)change(p<<1,l,mid,L,R,v,mx);
		if(R>mid)change(p<<1|1,mid+1,r,L,R,v,mx);
		update(p);
	}

	ll query(int p,int l,int r,int pos,int opt) {
		if(l==r) return opt==4?tree[p].mx:tree[p].hismx;
		int mid=(l+r)>>1;push_down(p);
		if(pos<=mid)return query(p<<1,l,mid,pos,opt);
		else return query(p<<1|1,mid+1,r,pos,opt);
	}
}T;

int main() {
	n=read(),m=read();
	for(int i=1;i<=n;i++)
		a[i]=read();
	T.build(1,1,n);
	for(int i=1;i<=m;i++) {
		int opt=read(),l=0,r=0,v=0,pos=0;
		if(opt>3)pos=read();
		else l=read(),r=read(),v=read();
		if(opt==1)T.change(1,1,n,l,r,v,-inf);
		if(opt==2)T.change(1,1,n,l,r,-v,0);
		if(opt==3)T.change(1,1,n,l,r,-inf,v);
		if(opt>3)printf("%lld\n",T.query(1,1,n,pos,opt));
	}
	return 0;
}
posted @ 2019-01-08 21:20  AKMer  阅读(360)  评论(0编辑  收藏  举报