E solution
每个魔法都是区间加的形式,我们很容易利用差分在 \(O(n+m)\) 的复杂度内求出所有魔法不失效的情况下,各个喷泉的高度。那么接下来就是变相的区间减,查询全局最小值了。
由于区间减互相独立,所以不需要用线段树一类的数据结构。
我们先维护出最大值所在的区间。即不考虑任何魔法失效的情况下,最大值出现的最小下标和最大下标。不妨将区间记为 \([ml,mr]\),最大值记为 \(mx\)。同时维护出前缀最大值和后缀最大值。
对于一次区间减,若修改范围为 \([ql,qr]\),区间减去 \(v\):
-
若 \(ql\le ml\),且 \(qr\ge mr\)。
此时可以确认之前维护的最大值全部被修改到,\([ql,qr]\) 内的最大值一定为 \(mx-v\)。拿 \(mx-v\) 与没有被修改到的区间中的最大值比大小就行。没修改到的区间一定是一段前缀和后缀,前后缀最大值数组已经维护好了。 -
否则至少有一个最大值没有被减掉。
这个最简单,\(mx\) 即为答案。
然后我们就可以 \(O(n+m)\) 解决此题。
#define N 200086
int t;
int n;
int a[N];
int pr[N],rp[N];//分别表示前缀最大和后缀最大
int c[N];//差分数组
int m;
class node{
public:
int l;
int r;
int v;
}q[200086];
signed main(){
std::ios::sync_with_stdio(0);
std::cin.tie(0);
std::cin>>t;
while(t--){
int ans=0;
std::cin>>n>>m;
for(int i=1;i<=n;i++){
std::cin>>a[i];
c[i]=a[i]-a[i-1];
}
for(int i=1;i<=m;i++){
std::cin>>q[i].l>>q[i].r>>q[i].v;
c[q[i].l]+=q[i].v;
c[q[i].r+1]-=q[i].v;
}
for(int i=1;i<=n;i++)
a[i]=a[i-1]+c[i];
memset(pr,-1,sizeof pr);
memset(rp,-1,sizeof rp);
for(int i=1;i<=n;i++)
pr[i]=std::max(pr[i-1],a[i]);
for(int i=n;i;i--)
rp[i]=std::max(rp[i+1],a[i]);
int maxn=-1e18;
int ll=0;
int rr=0;
for(int i=1;i<=n;i++)
if(a[i]>maxn){
maxn=a[i];
ll=rr=i;
}
else if(a[i]==maxn)
rr=i;
else;
//maxn 即为文中的 mx,ll rr 对应文中 ml,mr
for(int i=1;i<=m;i++){
int l=q[i].l;
int r=q[i].r;
int v=q[i].v;
if(l<=ll and r>=rr)
ans+=std::max(std::max(pr[l-1],rp[r+1]),maxn-v);
else
ans+=maxn;
}
std::cout<<ans<<"\n";
}
return 0;
}

浙公网安备 33010602011771号