题目描述:
链接: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;
}