牛客3566D- 小翔和泰拉瑞亞-線段樹

題目描述:

鏈接:https://ac.nowcoder.com/acm/contest/3566/D
來源:牛客網

小翔愛玩泰拉瑞亞 。
一天,他碰到了一幅地圖。這幅地圖可以分爲n列,第i列的高度爲Hi,他認爲這個地圖不好看,決定對它進行改造。
小翔又學會了m個魔法,實施第i個魔法可以使地圖的第Li列到第Ri列每一列的高度減少Wi,每個魔法只能實施一次,魔法的區間可能相交或包含。
小翔認爲,一幅地圖中最高的一列與最低的一列的高度差越大,這幅地圖就越美觀。
小翔可以選擇m個魔法中的任意一些魔法來實施,使得地圖儘量美觀。但是他不知道該如何選擇魔法,於是他找到了你。請你求出所有可行方案中,高度差的最大值。
對於100%的數據,滿足1≤n,m≤200000,-109≤Hi≤109,1≤Wi≤109,1≤Li≤Ri≤n。

輸入描述:

輸入文件的第一行包含兩個整數n,m。
輸入的第二行包含n個整數,相鄰兩數間用一個空格隔開,第i個整數爲Hi。
接下來的m行,每行包含3個整數,分別是Li,Ri,Wi,相鄰兩數間用一個空格隔開。

輸出描述:

一行一個整數,表示高度差的最大值。

輸入樣例:

3 3
7 -2 -10
1 3 4
3 3 4
1 2 8

輸出樣例:

21

核心思想:

線段樹,兩次建樹並處理。
1、建樹,將魔法按右端點升序排列,依次更新線段樹並更新ans。
2、建樹,將魔法按左端點降序排列,依次更新線段樹並更新ans。

詳見代碼!

代碼如下:

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=2e5+20;
int n,m;
ll h[N];//存儲原始高度,方便兩次建樹 
struct node{//存儲魔法信息 
	int l,r;
	ll w;
}a[N];
struct Node{
	int l,r;
	ll x,y,lazy;//x爲此樹高度的最小值,y爲最大值 
	Node(){
	}
	Node(ll xx,ll yy)
	{
		x=xx;
		y=yy;
	}
}tr[N<<2];
void pushup(int m)
{
	tr[m].x=min(tr[m<<1].x,tr[m<<1|1].x);
	tr[m].y=max(tr[m<<1].y,tr[m<<1|1].y);
	return; 
}
void pushdown(int m)
{
	if(tr[m].lazy)
	{
		ll t=tr[m].lazy;
		tr[m<<1].x+=t;
		tr[m<<1].y+=t;
		tr[m<<1].lazy+=t;
		tr[m<<1|1].x+=t;
		tr[m<<1|1].y+=t;
		tr[m<<1|1].lazy+=t;
		tr[m].lazy=0;
	}
	return;
}
void build(int m,int l,int r)
{
	tr[m].l=l;
	tr[m].r=r;
	tr[m].lazy=0;
	if(l==r)
	{
		tr[m].x=tr[m].y=h[l];
		return;
	}
	int mid=(l+r)>>1;
	build(m<<1,l,mid);
	build(m<<1|1,mid+1,r);
	pushup(m);
	return;
}
void update(int m,int l,int r,ll v)
{
	if(tr[m].l==l&&tr[m].r==r)
	{
		tr[m].lazy+=v;
		tr[m].x+=v;
		tr[m].y+=v;
		return;
	}
	pushdown(m);
	int mid=(tr[m].l+tr[m].r)>>1;
	if(r<=mid)
		update(m<<1,l,r,v);
	else if(l>mid)
		update(m<<1|1,l,r,v);
	else
	{
		update(m<<1,l,mid,v);
		update(m<<1|1,mid+1,r,v);
	}
	pushup(m);
	return;
}
bool cmp1(node x,node y)//右端點升序
{
	return x.r<y.r;
}
bool cmp2(node x,node y)//左端點降序 
{
	return x.l>y.l;
}
ll fun(ll ans,bool cmp(node,node))
{
	build(1,1,n);
	sort(a,a+m,cmp);
	for(int i=0;i<m;i++)
	{
		update(1,a[i].l,a[i].r,-a[i].w);
		ans=max(ans,tr[1].y-tr[1].x);
	}
	return ans;
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		scanf("%lld",&h[i]);
	ll x=2e9,y=-2e9;//x爲min,y爲max 
	for(int i=0;i<m;i++)
	{
		scanf("%d%d%lld",&a[i].l,&a[i].r,&a[i].w);
		x=min(x,a[i].w);
		y=max(y,a[i].w);
	}
	ll ans=y-x;
	ans=max(ans,fun(ans,cmp1));//右端點升序
	ans=max(ans,fun(ans,cmp2));//左端點降序 
	cout<<ans<<endl;
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章