【BZOJ3064】【Tyvj1518】CPU监控 裸线段树

#include <stdio.h>
int main()
{
	puts("转载请注明出处谢谢");
	puts("http://blog.csdn.net/vmurder/article/details/43271091");
}

题解:显然是裸的线段树,连区间合并都没有,更别提可持久化了。。。

水得一比,但是也相当恶心。。

维护一下:

目前线段 最大值、覆盖值、增加值、

历史线段 最大值、覆盖值、增加值。

然后覆盖值是赋-inf还是再加个flag记录有没有随便了。

总之很恶心,昨天晚上调了好久好久都没调过。

对了,这种恶心的东西不妨分多个线段树维护。

o(︶︿︶)o 、本来就感冒,晚上还熬夜,作死0:30去操场跑个步还撞到了铁门上。

Qwq。

贴代码吧,虽然没什么意义。

呃,我的define不是很难看的,不用抗拒的说~~wWW

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define inf 0x3f3f3f3f
#define ls note<<1
#define rs note<<1|1
#define N 101000
#define his hs[note]
#define my s[note]
using namespace std;
struct Segment_Tree
{
	int x,cover,add;
}s[N<<2],hs[N<<2];
inline void checkmax(int &x,int y){x=max(x,y);}
inline void h_add(int note,int v)
{
	checkmax(his.x,my.x+v);
	if(my.cover>-inf)checkmax(his.cover,my.cover+v);
	else checkmax(his.add,my.add+v);
}

inline void h_cover(int note,int v)
{
	checkmax(his.x,v);
	checkmax(his.cover,v);
}

inline void m_add(int note,int v)
{
	checkmax(his.x,my.x+=v);
	if(my.cover>-inf)checkmax(his.cover,my.cover+=v);
	else checkmax(his.add,my.add+=v);
}

inline void m_cover(int note,int v)
{
	checkmax(his.x,my.x=v);
	checkmax(his.cover,my.cover=v);
	my.add=0;
}

inline void pushdown(int note)
{
	if(his.add)
	{
		h_add(ls,his.add);
		h_add(rs,his.add);
		his.add=0;
	}
	if(his.cover>-inf)
	{
		h_cover(ls,his.cover);
		h_cover(rs,his.cover);
		his.cover=-inf;
	}
	if(my.add)
	{
		m_add(ls,my.add);
		m_add(rs,my.add);
		my.add=0;
	}
	if(my.cover>-inf)
	{
		m_cover(ls,my.cover);
		m_cover(rs,my.cover);
		my.cover=-inf;
	}
}

inline void pushup(int note)
{
	my.x=max(s[ls].x,s[rs].x);
	checkmax(his.x,max(hs[ls].x,hs[rs].x));
}
void build(int note,int l,int r)
{
	my.cover=his.cover=-inf;
	if(l==r)
	{
		scanf("%d",&my.x),his.x=my.x;
		return ;
	}
	int mid=l+r>>1;
	build(ls,l,mid),build(rs,mid+1,r);
	his.x=-inf,pushup(note);
}
void add(int note,int L,int R,int l,int r,int x)
{
	if(l<=L&&R<=r){m_add(note,x);return ;}
	pushdown(note);
	int mid=L+R>>1;
	if(l<=mid)add(ls,L,mid,l,r,x);
	if(r>mid)add(rs,mid+1,R,l,r,x);
	pushup(note);
}
void cover(int note,int L,int R,int l,int r,int x)
{
	if(l<=L&&R<=r){m_cover(note,x);return ;}
	pushdown(note);
	int mid=L+R>>1;
	if(l<=mid)cover(ls,L,mid,l,r,x);
	if(r>mid)cover(rs,mid+1,R,l,r,x);
	pushup(note);
}
int query(int note,int L,int R,int l,int r)
{
	if(l<=L&&R<=r)return my.x;
	pushdown(note);
	int mid=L+R>>1,ans=-inf;
	if(l<=mid)ans=max(ans,query(ls,L,mid,l,r));
	if(r>mid)ans=max(ans,query(rs,mid+1,R,l,r));
	return ans;
}
int ask(int note,int L,int R,int l,int r)
{
	if(l<=L&&R<=r)return his.x;
	pushdown(note);
	int mid=L+R>>1,ans=-inf;
	if(l<=mid)ans=max(ans,ask(ls,L,mid,l,r));
	if(r>mid)ans=max(ans,ask(rs,mid+1,R,l,r));
	return ans;
}
int n,m;
int main()
{
	char opt[5];
	int i,j,k;
	int a,b,c;

	scanf("%d",&n);
	build(1,1,n);
	for(scanf("%d",&m);m--;)
	{
		scanf("%s%d%d",opt,&a,&b);
		if(opt[0]=='Q')printf("%d\n",query(1,1,n,a,b));
		else if(opt[0]=='A')printf("%d\n",ask(1,1,n,a,b));
		else if(opt[0]=='P')
		{
			scanf("%d",&c);
			add(1,1,n,a,b,c);
		}
		else if(opt[0]=='C')
		{
			scanf("%d",&c);
			cover(1,1,n,a,b,c);
		}
	}
	return 0;
}
时间: 2024-09-28 13:36:12

【BZOJ3064】【Tyvj1518】CPU监控 裸线段树的相关文章

BZOJ1798题解 Seq维护序列题解 双tag裸线段树

BZOJ1798题解 Seq维护序列题解 双tag裸线段树 1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec  Memory Limit: 64 MBSubmit: 5549  Solved: 1951[Submit][Status][Discuss] Description 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)

10.25算法训练——裸线段树

题目大意:对N(1<=N<=50000)个数进行连续进行M(1<=M<=200000)次询问:问1-N之间任意连续区间最大值和最小值之差. 之前学过线段树,学的是模版题,求解的问题是在一段区间内任意加减,然后再询问任意一段之区间的和. 这次的问题和之前学的模版题相同之处是:查询的是一段连续区间的信息. 不同之处在于:区间求和问题需要在线段树的每个结点记录其左儿子和右儿子所有结点之和.也就是说每个结点的信息是一个数. 所以之后的查询操作,也是不断去访问线段树的结点,将这些结点上的数加

【bzoj3064】 CPU监控

http://www.lydsy.com/JudgeOnline/problem.php?id=3064 (题目链接) 题意 给出一个长度为$n$的数列$A$,同时定义一个辅助数组$B$,$B$开始与$A$完全相同.接下来进行$m$次操作, 有4种类型: 区间加法 区间覆盖 查询$A$的区间最值 查询$B$的区间最值 Solution 参考吉利论文. 最恶心的就是覆盖标记和加减标记的合并=  =,一定要想清楚所有情况. 细节 代码略丑=  = 代码 // bzoj3938 #include<al

POJ3264_Balanced Lineup(线段树/单点更新)

解题报告 题意: 求区间内最大值和最小值的差值. 思路: 裸线段树,我的线段树第一发.区间最值. #include <iostream> #include <cstring> #include <cstdio> #define inf 99999999 #define LL long long using namespace std; LL minn[201000],maxx[201000]; void update(LL root,LL l,LL r,LL p,LL

【USACO 2008 Nov Gold】 3.Light Switching(lites 开关灯) 区间修改线段树

题意: n.m,n个灯,m次操作 两种操作 0: 这段区间全部状态取反,初始全部为0 1: 询问这段区间有几个灯是亮的. 裸线段树,弱爆了. #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 101000 #define inf 0x3f3f3f3f using namespace std; struct Segment_Tree {

poj3468 线段树 or splay

poj3468  裸线段树.因为在熟悉splay 所以就用splay交了一发...开始用的scanf()!==2 居然TLE了...然后我就当单组测试数据做的 然后就过了  囧TZ #include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cstring> #include <cmath> using namespac

CPU监控 线段树裸题

LINK:bzoj3064 此题甚好码了20min停下来思考的时候才发现不对的地方有点坑... 还真不好写来着 可这的确是线段树的裸题...我觉得我写应该没有什么大问题 不过思路非常的紊乱 如果是自己写的话 所以为了自己能写出来 整理思路就是这篇博客了. Q X Y:询问从X到Y这段时间内CPU最高使用率 A X Y:询问从X到Y这段时间内之前列出的事件使CPU达到过的最高使用率 P X Y Z:列出一个事件这个事件使得从X到Y这段时间内CPU使用率增加Z C X Y Z:列出一个事件这个事件使

bzoj3064: Tyvj 1518 CPU监控 线段树

线段树维护两个值四个标记,注意打标记的顺序. #include<bits/stdc++.h> #define N (1<<18) #define M (l+r>>1) #define P (k<<1) #define S (k<<1|1) #define L l,M,P #define R M+1,r,S #define Z int l=1,int r=n,int k=1 using namespace std; int n; typedef i

BZOJ.3064.CPU监控(线段树 历史最值)

题目链接 \(Description\) 有一个长为n的序列Ai,要求支持查询[l,r]的最值.历史最值,区间加/重设 \(Solution\) 线段树,每个点再维护一个历史(从0到现在)最大值.历史(从上次下传标记到现在)最大的set,add标记 PushDown时肯定是先下放历史标记,之后再用当前标记更新 /* 要记得当要PushDown某个点时,last,now的val都是历史的(下传前),所以now.v + last.add就是下传前值+[下传前到现在]一次最大的修改的值 不能只在Set