1. 程式人生 > 其它 >[洛谷 P4314] CPU監控

[洛谷 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());
	}
}