CF1359D Yet Another Yet Another Task

题解的简单写法。

看到值域很小,而且限制我们快速求出贡献的是区间最大值,我们不妨枚举这个区间最大值 i ,位置是pi

假如 i 只有一个的话,那么 r 一定大于等于 pil 一定小于等于 pi

假如有多个的话,运用扫描线的思想,然后发现到 rpi,kl 就可以到 pi,k

然后线性维护 sl 最小值,枚举 r 即可(l 可以更新到 r 左边第一个 pi,k,类似双指针)。

但是你发现这样求的是最大值 x 的贡献,因为你不能保证 pi,k,pi,k+1 之间的数都小于 i

虽然这样求的有交集,但是总的并集是能够等价于原问题集合的。(最大值1,2,3 并起来就是 {1,2,3})。

这篇题解求得是最大值x 的贡献,也是一样的。

所以我们发现,枚举最值的时候,通常是满足不等关系。


貌似没有线段树做法。

sa的前缀和数组。

对于一个确定的右端点 r 和左端点 l,它对于答案的贡献是 srsl1max{ai},lir ,如果枚举右端点,令 cl=sl1+max{ai},li 。那么其实就是要求 1kr1min{ck}

线段树维护 ck 即可。

用单调栈求出 ai 左边第一个大于自己的数 ap,然后把 [p,i1]max{ai} 覆盖成 ar 即可。

然后你发现要维护 c ,你得维护 s 的最小值,和 max{ai}

时间复杂度 O(nlogn)

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;

int a[N], n, s[N];
int stk[N], top;

struct Node {
	int l, r;
	int s, a, v; // s[i] + a[i]
	int tag;
}tr[N << 2];

void pushup(int u) {
	tr[u].v=min(tr[u<<1].v,tr[u<<1|1].v);
	tr[u].s=min(tr[u<<1].s,tr[u<<1|1].s);
}

void pushdown(int u) {
	if (tr[u].tag != 2e9) {
		tr[u<<1].a=tr[u].tag,tr[u<<1].v=tr[u<<1].s+tr[u].tag;
		tr[u<<1|1].a=tr[u].tag,tr[u<<1|1].v=tr[u<<1|1].s+tr[u].tag;
		tr[u<<1|1].tag=tr[u<<1].tag=tr[u].tag;
		tr[u].tag = 2e9;
	} 
}

void build(int u,int l,int r) {
	tr[u]={l,r};
	tr[u].tag=2e9;
	if (l==r) {
		tr[u].a=1e9;
		tr[u].s=s[l];
		tr[u].v=tr[u].a+tr[u].s;
		tr[u].tag=2e9;
		return;
	}
	int mid = l +r>>1;
	build(u<<1,l,mid),build(u<<1|1,mid+1,r);
	pushup(u);
}

void modify(int u,int L,int R,int k) {
	if (tr[u].l>=L&&tr[u].r<=R) {
		tr[u].a=k;
		tr[u].v=tr[u].s+k;
		tr[u].tag=k;
		return ;
	}
	int mid=tr[u].l+tr[u].r>>1;
	pushdown(u);
	if (L<=mid) modify(u<<1,L,R,k);
	if (R>mid) modify(u<<1|1,L,R,k);
	pushup(u);
}

int query(int u,int L,int R) {
	if (tr[u].l>=L&&tr[u].r<=R) 
		return tr[u].v;
	int mid=tr[u].l+tr[u].r>>1;
	pushdown(u);
	int res=2e9;
	if (L<=mid) res=min(res,query(u<<1,L,R));
	if (R>mid) res=min(res,query(u<<1|1,L,R));
	return res;
}

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);
	for (int i = 1; i <= n; i ++ ) s[i] = s[i - 1] + a[i];
	
	int ans = 0;
	build(1,0,n);
	for (int i = 1; i <= n; i ++ ) {
		while (top && a[stk[top]] <= a[i]) top -- ;
		// [stk[top], i-1]拍成 a[i]+s[k]
		modify(1,stk[top],i-1,a[i]);
		ans=max(ans,s[i]-query(1,0,i-1));
		stk[ ++ top] = i;
	}
	cout << ans << endl;
	return 0;
}
posted @   Zlc晨鑫  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示