E solution

每个魔法都是区间加的形式,我们很容易利用差分在 \(O(n+m)\) 的复杂度内求出所有魔法不失效的情况下,各个喷泉的高度。那么接下来就是变相的区间减,查询全局最小值了。

由于区间减互相独立,所以不需要用线段树一类的数据结构。

我们先维护出最大值所在的区间。即不考虑任何魔法失效的情况下,最大值出现的最小下标和最大下标。不妨将区间记为 \([ml,mr]\),最大值记为 \(mx\)。同时维护出前缀最大值和后缀最大值。

对于一次区间减,若修改范围为 \([ql,qr]\),区间减去 \(v\)

  1. \(ql\le ml\),且 \(qr\ge mr\)
    此时可以确认之前维护的最大值全部被修改到,\([ql,qr]\) 内的最大值一定为 \(mx-v\)。拿 \(mx-v\) 与没有被修改到的区间中的最大值比大小就行。没修改到的区间一定是一段前缀和后缀,前后缀最大值数组已经维护好了。

  2. 否则至少有一个最大值没有被减掉。
    这个最简单,\(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;
}
posted @ 2025-07-19 16:44  立花廿七  阅读(27)  评论(0)    收藏  举报