uoj#164. 清华集训2015V

Posted thy_asdf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了uoj#164. 清华集训2015V相关的知识,希望对你有一定的参考价值。

传送门: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



*/


以上是关于uoj#164. 清华集训2015V的主要内容,如果未能解决你的问题,请参考以下文章

UOJ #164 清华集训2015 V

[uoj164][清华集训2015]V——线段树

清华集训2015 V

UOJ #46. 清华集训2014玄学

UOJ#38清华集训2014奇数国

UOJ#46. 清华集训2014玄学