题目链接:https://ac.nowcoder.com/acm/contest/3566/D
题目大意:
给定一个n元素数组,你有m个操作,每次操作可以选择一个区间[li,ri],将这个区间内的数减少vi,你可以选择其中一些进行操作,问你最后可以得到的最大值与最小值的差是多少?
思路:
因为每个操作是对于区间而言,我们不可能去遍历每个区间,所以需要更好的策略。
又因为题中说的是最大值与最小值的差,所以我们可以考虑固定一端,选择另一端。
于是,我们枚举每个位置i,然后选择操作,让i尽可能的小(也就是如果区间x包括了点i,我们就选择区间x),这样点i能够到达理想的最小值,此时我们再查询整个区间的最大值,就是一种可行的答案了,最后答案取所以位置的最大值就完了。
因为一个点可能被很多个区间覆盖,我们并不是暴力加,在从左往右遍历的过程中,在每个区间的左端点l插入这个区间,在区间的右端点r+1处删除这个区间,这样每个区间只会被update两次,就能更新到每个位置i啦。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
struct TreeNode{
int l,r;
ll maxx;
ll minn;
ll lazy;
}Tree[maxn<<2];
ll a[maxn];
void push_up(int root){
Tree[root].maxx=max(Tree[root<<1].maxx,Tree[root<<1|1].maxx);
Tree[root].minn=min(Tree[root<<1].minn,Tree[root<<1|1].minn);
}
void Build(int root,int l,int r){
Tree[root].l=l,Tree[root].r=r;
if(l==r){
Tree[root].maxx=Tree[root].minn=a[l];
Tree[root].lazy=0;
return ;
}
int mid=(l+r)>>1;
Build(root<<1,l,mid);
Build(root<<1|1,mid+1,r);
push_up(root);
}
void push_down(int root){
if(Tree[root].lazy){
Tree[root<<1].lazy+=Tree[root].lazy;
Tree[root<<1|1].lazy+=Tree[root].lazy;
Tree[root<<1].minn+=Tree[root].lazy;
Tree[root<<1|1].maxx+=Tree[root].lazy;
Tree[root<<1|1].minn+=Tree[root].lazy;
Tree[root<<1].maxx+=Tree[root].lazy;
Tree[root].lazy=0;
}
}
void update(int root,int l,int r,int v){
if(Tree[root].l>=l&&Tree[root].r<=r){
Tree[root].minn+=v;
Tree[root].maxx+=v;
Tree[root].lazy+=v;
return ;
}
push_down(root);
int mid=(Tree[root].l+Tree[root].r)>>1;
if(r<=mid){
update(root<<1,l,r,v);
}
else if(l>mid){
update(root<<1|1,l,r,v);
}
else{
update(root<<1,l,mid,v);
update(root<<1|1,mid+1,r,v);
}
push_up(root);
}
ll query(int root,int l,int r,int opt){
if(Tree[root].l>=l&&Tree[root].r<=r){
return opt==1?Tree[root].maxx:Tree[root].minn;
}
push_down(root);
int mid=(Tree[root].l+Tree[root].r)>>1;
if(r<=mid){
return query(root<<1,l,r,opt);
}
else if(l>mid){
return query(root<<1|1,l,r,opt);
}
else{
if(opt==1){
return max(query(root<<1,l,mid,opt),query(root<<1|1,mid+1,r,opt));
}
else{
return min(query(root<<1,l,mid,opt),query(root<<1|1,mid+1,r,opt));
}
}
}
struct Seg{
int l,r;
ll val;
}seg[maxn];
vector<int>L[maxn];
vector<int>R[maxn];
int cmp(const Seg a,const Seg b){
return a.l<b.l||(a.l==b.l&&a.r<b.r);
}
//快读
inline int Read()
{
int res=0,ch,flag=0;
if((ch=getchar())=='-')
flag=1;
else if(ch>='0'&&ch<='9')
res=ch-'0';
while((ch=getchar())>='0'&&ch<='9')
res=res*10+ch-'0';
return flag?-res:res;
}
inline ll Readll()
{
ll res=0,ch,flag=0;
if((ch=getchar())=='-')
flag=1;
else if(ch>='0'&&ch<='9')
res=ch-'0';
while((ch=getchar())>='0'&&ch<='9')
res=res*10+ch-'0';
return flag?-res:res;
}
signed main(){
int n,m;
n=Read(),m=Read();
for(int i=1;i<=n;i++){
a[i]=Readll();
}
Build(1,1,n);
for(int i=1;i<=m;i++){
seg[i].l=Read(),seg[i].r=Read(),seg[i].val=Readll();
}
sort(seg+1,seg+m+1,cmp);
for(int i=1;i<=m;i++){
L[seg[i].l].push_back(i);
R[seg[i].r+1].push_back(i);
}
ll ans=0;
for(int i=1;i<=n;i++){
for(int j=0;j<L[i].size();j++){
update(1,seg[L[i][j]].l,seg[L[i][j]].r,-seg[L[i][j]].val);
}
for(int j=0;j<R[i].size();j++){
update(1,seg[R[i][j]].l,seg[R[i][j]].r,seg[R[i][j]].val);
}
ll now=query(1,i,i,2);
ll maxx=query(1,1,n,1);
ans=max(ans,maxx-now);
}
printf("%lld\n",ans);
return 0;
}