題目鏈接: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;
}