首页 > 其他分享 >【题解】CF280D k-Maximum Subsequence Sum

【题解】CF280D k-Maximum Subsequence Sum

时间:2023-02-15 18:02:44浏览次数:34  
标签:lmx 题解 sum Maximum Subsequence lmn now rmn rmx

题目分析:

(可能是刚做完毒瘤 Ynoi 的原因,看这个 4k 的线段树感觉好简单)

可以看一下这个查询的操作,最多 \(k\) 个不重线段的和的最大值,这个东西大概是网络流的经典题吧。
具体做法就是 \(S\) 向 \(i\) 连流量为 \(1\) 费用为 \(0\) 的边,\(i\) 向 \(T\) 连流量为 \(1\) 费用为 \(0\) 的边,\(i\) 向 \(i+1\) 连流量为 \(1\) 费用为 \(a_i\) 的边。这样我们每次多一点流量,就意味着多选择一个区间,因为区间必然不可能相互包含。

我们费用流其实每次就是找一个最优的增广路然后去增广啊,而一条增广路也就必然对应了一段区间,如果增广路包含之前选择过的点其实就是意味着走反向边。也就是说,如果我们先选择了 \([1,3]\) 然后选择了 \([3,5]\),那么我们实际选择的区间就是 \([1,2]\) 和 \([4,5]\)。

那么这个题的思路就很清晰了。每次最优的增广路其实就是意味着区间最大子段和,而选择一条增广路就意味着区间取反,就很好维护了。

代码:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
struct sgement{
	int l,r,sum;
};
sgement operator + (sgement a,sgement b){
	return {a.l,b.r,a.sum + b.sum};
}
bool operator < (sgement a,sgement b){
	return a.sum < b.sum;
}
struct node{
	sgement sum,lmx,rmx,mx,lmn,rmn,mn;
}t[4 * N];
bool tag[4*N];
int a[N];
node merge(node a,node b){
	node c;
	c.sum = a.sum + b.sum;
	c.lmx = max(a.lmx,a.sum + b.lmx);
	c.rmx = max(b.rmx,a.rmx + b.sum);
	c.mx = max(max(a.mx,b.mx),a.rmx + b.lmx);
	c.lmn = min(a.lmn,a.sum + b.lmn);
	c.rmn = min(b.rmn,a.rmn + b.sum);
	c.mn = min(min(a.mn,b.mn),a.rmn + b.lmn);
	return c;
}
void rever(int now){
	t[now].sum.sum = -t[now].sum.sum;
	t[now].mx.sum = -t[now].mx.sum;
	t[now].mn.sum = -t[now].mn.sum;
	t[now].lmx.sum = -t[now].lmx.sum;
	t[now].rmx.sum = -t[now].rmx.sum;
	t[now].lmn.sum = -t[now].lmn.sum;
	t[now].rmn.sum = -t[now].rmn.sum;
	swap(t[now].mx,t[now].mn);swap(t[now].lmx,t[now].lmn);swap(t[now].rmx,t[now].rmn);
	tag[now] ^= 1;
}
void pushdown(int now){
	if(tag[now]){
		rever(now<<1);rever(now<<1|1);
		tag[now] = false;
	}
}
void rev(int now,int now_l,int now_r,int l,int r){
	if(l <= now_l && r >= now_r){
		rever(now);
		return;
	}
	pushdown(now);
	int mid = (now_l + now_r)>>1;
	if(l <= mid)	rev(now<<1,now_l,mid,l,r);
	if(r > mid)		rev(now<<1|1,mid+1,now_r,l,r);
	t[now] = merge(t[now<<1],t[now<<1|1]);
}
void modify(int now,int now_l,int now_r,int pos,int val){
	if(now_l == now_r){
		t[now].sum.sum = val;
		t[now].lmx.sum = max(val,0);t[now].rmx.sum = max(val,0);t[now].mx.sum = max(val,0);
		t[now].lmn.sum = min(val,0);t[now].rmn.sum = min(val,0);t[now].mn.sum = min(val,0);
		return;
	}
	pushdown(now);
	int mid = (now_l + now_r)>>1;
	if(pos <= mid)	modify(now<<1,now_l,mid,pos,val);
	if(pos > mid)	modify(now<<1|1,mid+1,now_r,pos,val);
	t[now] = merge(t[now<<1],t[now<<1|1]);
}
node query(int now,int now_l,int now_r,int l,int r){
	if(l <= now_l && r >= now_r)	return t[now];
	pushdown(now);
	int mid = (now_l + now_r)>>1;
	if(r <= mid)	return query(now<<1,now_l,mid,l,r);
	if(l > mid)		return query(now<<1|1,mid+1,now_r,l,r);
	return merge(query(now<<1,now_l,mid,l,r),query(now<<1|1,mid+1,now_r,l,r));
}
void build(int now,int now_l,int now_r){
	if(now_l == now_r){
		t[now].sum = {now_l,now_l,a[now_l]};
		t[now].lmx = {now_l,now_l,max(a[now_l],0)};
		t[now].rmx = {now_l,now_l,max(a[now_l],0)};
		t[now].mx = {now_l,now_l,max(a[now_l],0)};
		t[now].lmn = {now_l,now_l,min(a[now_l],0)};
		t[now].rmn = {now_l,now_l,min(a[now_l],0)};
		t[now].mn = {now_l,now_l,min(a[now_l],0)};
		return;
	}
	int mid = (now_l + now_r)>>1;
	build(now<<1,now_l,mid);build(now<<1|1,mid+1,now_r);
	t[now] = merge(t[now<<1],t[now<<1|1]);
}
int main(){
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	int n;scanf("%d",&n);
	for(int i=1; i<=n; i++)	scanf("%d",&a[i]);
	build(1,1,n);
	int m;scanf("%d",&m);
	for(int i=1; i<=m; i++){
		int opt;scanf("%d",&opt);
		if(opt == 0){
			int x,y;scanf("%d%d",&x,&y);
			modify(1,1,n,x,y);
		}
		else{
			int l,r,k;scanf("%d%d%d",&l,&r,&k);
			int ans = 0;
			vector<node> v;
			while(k--){
				node p = query(1,1,n,l,r);
				if(p.mx.sum <= 0)	break;
				v.push_back(p);
				ans += p.mx.sum;
				rev(1,1,n,p.mx.l,p.mx.r);
			}
			for(auto i : v)	rev(1,1,n,i.mx.l,i.mx.r);
			v.clear();
			printf("%d\n",ans);
		}
	}
	return 0;
}

标签:lmx,题解,sum,Maximum,Subsequence,lmn,now,rmn,rmx
From: https://www.cnblogs.com/linyihdfj/p/17124131.html

相关文章

  • 【题解】Luogu P3939 数颜色
    题目分析:解法一:显然我们可以直接对每一种颜色建一棵线段树,然后剩下的操作就非常简单了。代码:点击查看代码#include<bits/stdc++.h>usingnamespacestd;constint......
  • hadoop之shuffle阶段相关面试题解析
    --思考1:map()方法写出的数据存储到哪里?                                  --内存中1、在内存中存有一个环形缓冲区,该缓冲......
  • [省选联考 2022] 填树 题解
    神奇dp。发现我看到dp大多数时候只会暴力。那我约等于退役了啊。题意:自己看。首先有一个显然的暴力。枚举一个最小值\(L\),然后区间就限定在了\([L,L+K]\)。那么普及......
  • NOIP2015 普及组 推销员题解
    原题链接给定一个数轴,数轴上有一些点,第\(i\)个点离起点的距离是\(S_i\),取走它要消耗\(A_i\)的代价,同时在数轴上每移动一格要\(1\)的代价,路线只能从数轴......
  • CSP2022 假期计划 题解
    给你一张\(n\)个点,\(m\)条边的无向图,每个点有点权,要求你在图中选出\(A\),\(B\),\(C\),\(D\)四个点,使得\(1\rightarrowA\rightarrowB\rightarrowC\righ......
  • DTOJ 2023.02.11 测试 题解
    DTOJ2023.02.11测试题解2023省选模拟Round#12\(100+8+50=158\)还行T2想到了,但是没写,我觉得写了也不一定写得出来,挺妙的T1题意http://59.61.75.5:18018/p/545......
  • 读者最需要什么样的题解
    哈哈,其实还是鲜花,主要是看到\(\text{f}\color{red}{\text{eecle6418}}\)的这篇题解有感而发,当然我自己写的题解也很抽象,需要改正。当然这里的写题解是指主动打算写一......
  • 小孩召开法 题解
    开题之前の一些废话:小孩召开法,旦写一北砬。梦厷停留在,破了大式様。——龚诗锋《炄勺,砒》小孩。又是我很不会的排列计数。而且神题。久仰大名。现在是2月13日......
  • ARC120C Swaps 2 题解
    好难啊,会也不会设\(a_i=x,a_{i+1}=y\),那么交换后\(a_i=y+1,a_{i+1}=x-1\),发现交换后就是\(a_i+i\)和\(a_{i+1}+i+1\)这两个值进行了交换。那就把所有\(a_i\)变成......
  • 青龙面板调试运行代码时打印语句可能不执行的问题解决
    记录一次用青龙面板调试调用chatGPT的API时发现的一个问题:脚本在调试运行时,有可能会不显示部分打印语句的,例如node.js(python也有这种情况),如下图:关于为什么会出现此问题......