3064: Tyvj 1518 CPU监控

3064: Tyvj 1518 CPU监控

Time Limit: 20 Sec   Memory Limit: 256 MB
Submit: 747   Solved: 292
[ Submit][ Status][ Discuss]

Description

Bob需要一个程序来监视CPU使用率。这是一个很繁琐的过程,为了让问题更加简单,Bob会慢慢列出今天会在用计算机时做什么事。 
Bob会干很多事,除了跑暴力程序看视频之外,还会做出去玩玩和用鼠标乱点之类的事,甚至会一脚踢掉电源……这些事有的会让做这件事的这段时间内CPU使用率增加或减少一个值;有的事还会直接让CPU使用率变为一个值。 
当然Bob会询问:在之前给出的事件影响下,CPU在某段时间内,使用率最高是多少。有时候Bob还会好奇地询问,在某段时间内CPU曾经的最高使用率是多少。 
为了使计算精确,使用率不用百分比而用一个整数表示。 
不保证Bob的事件列表出了莫名的问题,使得使用率为负……………… 

Input

第一行一个正整数T,表示Bob需要监视CPU的总时间。 
然后第二行给出T个数表示在你的监视程序执行之前,Bob干的事让CPU在这段时间内每个时刻的使用率达已经达到了多少。 
第三行给出一个数E,表示Bob需要做的事和询问的总数。 
接下来E行每行表示给出一个询问或者列出一条事件: 
Q X Y:询问从X到Y这段时间内CPU最高使用率 
A X Y:询问从X到Y这段时间内之前列出的事件使CPU达到过的最高使用率 
P X Y Z:列出一个事件这个事件使得从X到Y这段时间内CPU使用率增加Z 
C X Y Z:列出一个事件这个事件使得从X到Y这段时间内CPU使用率变为Z 
时间的单位为秒,使用率没有单位。 
X和Y均为正整数(X<=Y),Z为一个整数。 
从X到Y这段时间包含第X秒和第Y秒。 
保证必要运算在有符号32位整数以内。 

Output

对于每个询问,输出一行一个整数回答。 

Sample Input

10
-62 -83 -9 -70 79 -78 -31 40 -18 -5
20
A 2 7
A 4 4
Q 4 4
P 2 2 -74
P 7 9 -71
P 7 10 -8
A 10 10
A 5 9
C 1 8 10
Q 6 6
Q 8 10
A 1 7
P 9 9 96
A 5 5
P 8 10 -53
P 6 6 5
A 10 10
A 4 4
Q 1 5
P 4 9 -69

Sample Output

79
-70
-70
-5
79
10
10
79
79
-5
10
10

HINT

 数据分布如下: 

第1、2个数据保证T和E均小于等于1000 

第3、4个数据保证只有Q类询问 

第5、6个数据保证只有C类事件 

第7、8个数据保证只有P类事件 

全部数据保证T和E均小于等于100000 

Source

[ Submit][ Status][ Discuss]

几乎花了半天时间来调这一题,,整个人都不太好了。。。。。。
简明题意,,给一个数组,要求支持:
1.询问区间最值
2.询问区间历史最值(即这个区间历史上出现过的最大值)
3.区间加减
4.区间覆盖
显然是要用线段树做,,具体做法见吉如一的论文(话说这居然属于最简单的一类?!),此处补一点笔记
线段树上每个点维护:
A[o]:当前最值,B[o]:历史最值,Add[o]:加法懒惰标记 
Pa[o]:历史加法最值,Mark[o]:区间覆盖标记,Pm[o]:历史覆盖最值
先不考虑区间覆盖操作,,区间加法会在线段树上定位log个区间,对于这些区间,Add[o]的维护十分容易
定义Pa[o]就是历史上在该点打下的标记中,累计最大的时刻的标记和
比如,有一系列的P操作同时作用于该点,,+7 +9 -2 +6 -5
那么Pa[o] = 20,也就是第四次操作后的结果,因为这次是5次里累计最大的
考虑标记下传,Pa[son] = max(Pa[son],Add[son] + Pa[o]),Add[son] += Add[o]
为什么这样做是对的??在打标记的时候,儿子出现了更早的标记,那么说明对儿子的操作都是之前完成了的
对于之前的最优结果,Pa[son]已经储存,如果要知道能不能更优,当然是之前的操作和 + 当前的最优决策
这样,对于不存在覆盖操作的简易版已经解决

接下来,增添覆盖操作,对于一个节点,如果在这里打过一个覆盖标记,
那么,之后如果再操作这个节点,无论是操作3还是操作4,都和区间覆盖无异
因此,在打标记的时候特判该点有无Mark标记,如果有,直接对Mark和Pm更新,对于操作3,转化一下就行
这种情况要一直持续到下次把这个点的标记下传掉
综上,每次下传标记,有B[o] = max{B[o],max(A[o] + Pa[o],Pm[o])}
即先考虑第一阶段++--能取得的最优结果,在考虑第二阶段被反复覆盖能取得的最优结果

但是,,写起来简直是WA飞。。。。。
一开始给Add标记赋的居然是-INF而不是0。。。
然后,,下传标记的时候儿子还要特判是否被Mark过,否则特殊处理
最后,,Mark的修改时强行变更,,作死取max???
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<bitset>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;

const int maxn = 1E5 + 10;
const int T = 4;
typedef long long LL;
const LL INF = 1E16;
const char com[4] = {'Q','A','P','C'};

int n,m;
LL A[maxn*T],B[maxn*T],Add[maxn*T],Pa[maxn*T],Mark[maxn*T],Pm[maxn*T];

int getint()
{
	char ch = getchar(); int ret = 0,a = 1;
	while (ch < '0' || '9' < ch)
	{
		if (ch == '-') a = -1;
		ch = getchar();
	}
	while ('0' <= ch && ch <= '9')
		ret = ret*10 + ch - '0',ch = getchar();
	return ret * a;
}

void Clear(int o) 
{
	Add[o] = Pa[o] = 0;
	Mark[o] = Pm[o] = -INF;
}

void maintain(int o)
{
	int lc = (o<<1),rc = (o<<1|1);
	A[o] = max(A[lc],A[rc]);
	B[o] = max(B[lc],B[rc]);
}

void Down(int o,LL AD,LL P)
{
	if (Pm[o] != -INF) Pm[o] = max(Pm[o],Mark[o] + P),Mark[o] += AD;
	else Pa[o] = max(Pa[o],Add[o] + P),Add[o] += AD;
}

void pushdown(int o,int l,int r)
{
	if (Add[o] == 0 && Mark[o] == -INF) return;
	B[o] = max(B[o],max(A[o] + Pa[o],Pm[o]));
	int lc = (o<<1),rc = (o<<1|1),mid = (l + r) >> 1;
	if (Add[o] != 0)
	{
		A[o] += Add[o];
		if (l < r) Down(lc,Add[o],Pa[o]),Down(rc,Add[o],Pa[o]);
	}
	if (Mark[o] != -INF)
	{
		A[o] = Mark[o];
		if (l < r)
		{
			Mark[lc] = Mark[rc] = Mark[o];
			Pm[lc] = max(Pm[lc],Pm[o]);
			Pm[rc] = max(Pm[rc],Pm[o]);
		}
	}
	Clear(o);
}

void Build(int o,int l,int r)
{
	if (l == r)
	{
		Clear(o); A[o] = B[o] = getint(); return;
	}
	int mid = (l + r) >> 1; Clear(o);
	Build(o<<1,l,mid); Build(o<<1|1,mid+1,r);
	maintain(o);
}

void Modify(int o,int l,int r,int ml,int mr,LL k,int typ)
{
	if (ml <= l && r <= mr)
	{
		if (typ == 2)
		{
			if (Pm[o] != -INF) Mark[o] += k,Pm[o] = max(Pm[o],Mark[o]);
			else Add[o] += k,Pa[o] = max(Pa[o],Add[o]);
		}
		else Mark[o] = k,Pm[o] = max(Pm[o],k);
		pushdown(o,l,r); return;
	}
	int mid = (l + r) >> 1; pushdown(o,l,r);
	if (ml <= mid) Modify(o<<1,l,mid,ml,mr,k,typ); else pushdown(o<<1,l,mid);
	if (mr > mid) Modify(o<<1|1,mid+1,r,ml,mr,k,typ); else pushdown(o<<1|1,mid+1,r);
	maintain(o);
}

LL Query(int o,int l,int r,int ql,int qr,int typ)
{
	pushdown(o,l,r);
	if (ql <= l && r <= qr) return !typ? A[o] : B[o];
	int mid = (l + r) >> 1; LL ret = -INF;
	if (ql <= mid) ret = Query(o<<1,l,mid,ql,qr,typ);
	if (qr > mid) ret = max(ret,Query(o<<1|1,mid+1,r,ql,qr,typ));
	return ret;
}

int getcom()
{
	char ch = getchar();
	for (;;)
	{
		for (int i = 0; i < 4; i++)
			if (ch == com[i]) return i;
		ch = getchar();
	}
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
	#endif
	
	n = getint(); Build(1,1,n); m = getint();
	while (m--)
	{
		int typ = getcom(),l,r;
		l = getint(); r = getint();
		if (typ == 0) printf("%lld\n",Query(1,1,n,l,r,0));
		else if (typ == 1) printf("%lld\n",Query(1,1,n,l,r,1));
		else if (typ == 2) Modify(1,1,n,l,r,getint(),2);
		else Modify(1,1,n,l,r,getint(),3);
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值