**
**
这道题很巧妙,关键就是想明白,我们先对所有的修改按照左端点排序,然后遍历到某一个位置的时候我们假定这个位置是最低点,因此我们首先做的操作时将以此点为左端点的所有能够修改的区间全部修改了,因为前面的每个点也是这么做的,因此可以保证枚举到这个点并操作完后所有包含这个区间的魔法都被施展了,即这个最低点尽量的低。
然后更新完答案后再将所有以这个点为右端点的操作全部撤销,即加上-d,这样子可以保证再更新下一个区间的时候能够使得所有不包含当前点的魔法不会被施展。
总之,思维有深度,实现起来则非常容易。
#define int LL
const int N = 200010;
int n,m,k,h[N],ans=0;
struct Node{
int l,r;
int mx,mn,add;
}tr[N<<2];
vector<pii> add[N], del[N];
void push_up(int u){
tr[u].mx=max(tr[u<<1].mx, tr[u<<1|1].mx);
tr[u].mn=min(tr[u<<1].mn, tr[u<<1|1].mn);
tr[u].add=0;
}
void calc(Node& u,int add){
u.mx += add;
u.mn += add;
u.add += add;
}
void push_down(int u){
if(tr[u].add){
calc(tr[u<<1], tr[u].add);
calc(tr[u<<1|1], tr[u].add);
tr[u].add=0;
}
}
void build(int u,int l,int r){
tr[u]={l,r};
if(l==r){
tr[u].add=0;
tr[u].mx=tr[u].mn=h[l];
return ;
}
int mid=l+r>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
push_up(u);
}
void modify(int u,int l,int r,int d){
if(tr[u].l>=l&&tr[u].r<=r){
calc(tr[u], d);
return ;
}
push_down(u);
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid) modify(u<<1,l,r,d);
if(r>mid) modify(u<<1|1,l,r,d);
push_up(u);
}
Node query(int u,int l,int r){
if(tr[u].l>=l&&tr[u].r<=r){
return tr[u];
}
int mid=tr[u].l+tr[u].r>>1;
if(r<=mid) return query(u<<1,l,r);
if(l>mid) return query(u<<1|1,l,r);
auto left=query(u<<1,l,r),right=query(u<<1|1,l,r);
Node ans;
ans.mx=max(left.mx, right.mx);
ans.mn=min(left.mn, right.mn);
return ans;
}
void solve(){
n=read(),m=read();
rep(i,1,n) h[i]=read();
rep(i,1,m){
int l=read(),r=read(),w=read();
add[l].push_back({r,w});
del[r].push_back({l,w});
}
build(1,1,n);
ans=max(ans,tr[1].mx-tr[1].mx);
rep(i,1,n){
for(auto u:add[i]) {
int l=i,r=u.x,w=u.y;
modify(1,l,r,-w);
}
ans=max(ans,tr[1].mx-tr[1].mn);
for(auto u:del[i]){
int l=u.x,r=i,w=u.y;
modify(1,l,r,w);
}
}
print(ans);
}