ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[洛谷 P4314] CPU监控

2021-08-24 12:01:30  阅读:144  来源: 互联网

标签:return 标记 最大值 洛谷 down P4314 加法 操作 CPU


一、题目

点此看题

二、解法

第一次过历史线段树的题,写篇题解纪念一下

核心思想就是将标记看作一个操作序列,我们需要额外维护一个序列前缀最大值。

具体来说:我们维护 icv,cv,hcv 表示是否被覆盖\(/\)当前的覆盖标记\(/\)历史覆盖标记最大值;维护 ad,had 表示当前的加法标记\(/\)历史加法标记最大值;维护 mx/hmx 表示区间最大值\(/\)历史区间最大值。

关键之处:考虑如何下传,因为在 \(cover\) 操作的时候我们要清空 \(ad\),那么我们要先把加法标记先下传,不能先下传覆盖标记是因为这样会直接破坏儿子的加法标记。注意在操作序列出现 \(cover\) 之后,我们就不能直接进行加法操作了,因为这样标记会混乱,但是我们能很容易的把加法操作等价转化成覆盖操作。

总结一句:对于历史问题,想象一个操作序列来思考,要考虑操作之间的互相影响,可以把操作序列“分段”来解决这种影响,比如本题就是以 \(cover\) 操作来分段的(以后的操作就只用 \(cover\))。

#include <cstdio>
#include <iostream>
using namespace std;
const int M = 100005;
const int inf = -2147483648;
int read()
{
    int x=0,f=1;char c;
    while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    return x*f;
}
int n,m;char s[10];
struct tree
{
	int icv,hcv,cv,had,ad,mx,hmx;
	tree() {icv=hcv=cv=had=ad=0;mx=hmx=inf;}
	void cover(int d,int hd)
	{
		if(icv) hcv=max(hcv,hd);
		else hcv=hd,icv=1;
		mx=cv=d;
		hmx=max(hmx,hd);
		ad=0;
	}
	void Add(int d,int hd)
	{
		had=max(had,ad+hd);
		hmx=max(hmx,mx+hd);
		ad+=d;mx+=d;
	}
	void add(int d,int hd)
	{
		if(icv) cover(cv+d,cv+hd);
		else Add(d,hd);
	}
}tr[4*M];
void down(int i)
{
	//download the add tag
	tr[i<<1].add(tr[i].ad,tr[i].had);
	tr[i<<1|1].add(tr[i].ad,tr[i].had);
	tr[i].ad=tr[i].had=0;
	//download the covering tag
	if(tr[i].icv)
	{
		tr[i<<1].cover(tr[i].cv,tr[i].hcv);
		tr[i<<1|1].cover(tr[i].cv,tr[i].hcv);
		tr[i].icv=tr[i].hcv=tr[i].cv=0;
	}
}
void up(int i)
{
	tr[i].mx=max(tr[i<<1].mx,tr[i<<1|1].mx);
	tr[i].hmx=max(tr[i].hmx,tr[i].mx);
}
void cov(int i,int l,int r,int L,int R,int x)
{
	if(l>R || L>r) return ;
	if(L<=l && r<=R)
	{
		tr[i].cover(x,x);
		return ;
	}
	int mid=(l+r)>>1;down(i);
	cov(i<<1,l,mid,L,R,x);
	cov(i<<1|1,mid+1,r,L,R,x);
	up(i);
}
void add(int i,int l,int r,int L,int R,int x)
{
	if(l>R || L>r) return ;
	if(L<=l && r<=R)
	{
		tr[i].add(x,x);
		return ;
	}
	int mid=(l+r)>>1;down(i);
	add(i<<1,l,mid,L,R,x);
	add(i<<1|1,mid+1,r,L,R,x);
	up(i);
}
int ask(int i,int l,int r,int L,int R)
{
	if(L>r || l>R) return inf;
	if(L<=l && r<=R) return tr[i].mx;
	int mid=(l+r)>>1;down(i);
	return max(ask(i<<1,l,mid,L,R),
	ask(i<<1|1,mid+1,r,L,R));
}
int hask(int i,int l,int r,int L,int R)
{
	if(L>r || l>R) return inf;
	if(L<=l && r<=R) return tr[i].hmx;
	int mid=(l+r)>>1;down(i);
	return max(hask(i<<1,l,mid,L,R),
	hask(i<<1|1,mid+1,r,L,R));
}
void build(int i,int l,int r)
{
	if(l==r)
	{
		tr[i].mx=tr[i].hmx=read();
		return ;
	}
	int mid=(l+r)>>1;
	build(i<<1,l,mid);
	build(i<<1|1,mid+1,r);
	up(i);
}
signed main()
{
	n=read();build(1,1,n);
	m=read();
	while(m--)
	{
		scanf("%s",s);int l=read(),r=read();
		if(s[0]=='Q') printf("%d\n",ask(1,1,n,l,r));
		if(s[0]=='A') printf("%d\n",hask(1,1,n,l,r));
		if(s[0]=='P') add(1,1,n,l,r,read());
		if(s[0]=='C') cov(1,1,n,l,r,read());
	}
}

标签:return,标记,最大值,洛谷,down,P4314,加法,操作,CPU
来源: https://www.cnblogs.com/C202044zxy/p/15179707.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有