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\n",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\n",T.query(x,0));
		else if (op==5) scanf("%d",&x),printf("%lld\n",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



*/


posted @ 2016-04-26 10:37  orzpps  阅读(339)  评论(0编辑  收藏  举报