CF280D k-Maximum Subsequence Sum
WC现在正在讲网络流,我也来写一题网络流!
一开始真想不到这题能费用流。但是 \(k\) 规模较小告诉我们可以先从一个一个区间贪心做入手。但是纯贪心一定是不对的,所以可以考虑反悔贪心(我觉得这题反悔贪心思路可能还要更简单一点?)。从费用流角度可以更好地描述反悔贪心的思路。
连边 \(i \rightarrow i + 1\),流了这条边就表示选 \(i\) 这个点,然后最大费用最大流就是答案。
直接上线段树模拟找增广路,需要维护单点修改,区间乘 \(-1\),区间最大子段和。
这就比较复杂了,建议想明白再写,正负需要分别维护,还要维护最大字段和的端点,我一个节点维护了 16 个值。
写了好长。
#include <cstdio>
#include <iostream>
#define int long long
using std::swap;
namespace IO {
#define isdigit(x) (x >= '0' && x <= '9')
template<typename T>
inline void read(T &x) {
x = 0; char ch = getchar(); int f = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
if(f) x = -x;
}
template<typename T>
inline void write(T x) {
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
#undef isdigit
}
using namespace IO;
const int N = 1e5 + 10;
const int inf = 1e15;
int n, a[N];
struct Msg {
int val1, lmx1, rmx1, lp1, rp1, pre1, suf1, val2, lmx2, rmx2, lp2, rp2, pre2, suf2, sum;
inline Msg operator + (const Msg y) const{
Msg res{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
res.sum = sum + y.sum;
if(lmx1 > sum + y.lmx1) {
res.pre1 = pre1;
res.lmx1 = lmx1;
} else {
res.pre1 = y.pre1;
res.lmx1 = sum + y.lmx1;
}
if(y.rmx1 > y.sum + rmx1) {
res.suf1 = y.suf1;
res.rmx1 = y.rmx1;
} else {
res.suf1 = suf1;
res.rmx1 = y.sum + rmx1;
}
res.lp1 = suf1, res.rp1 = y.pre1;
res.val1 = rmx1 + y.lmx1;
if(res.val1 < val1)
res.val1 = val1, res.lp1 = lp1, res.rp1 = rp1;
if(res.val1 < y.val1)
res.val1 = y.val1, res.lp1 = y.lp1, res.rp1 = y.rp1;
if(lmx2 > -sum + y.lmx2) {
res.pre2 = pre2;
res.lmx2 = lmx2;
} else {
res.pre2 = y.pre2;
res.lmx2 = -sum + y.lmx2;
}
if(y.rmx2 > -y.sum + rmx2) {
res.suf2 = y.suf2;
res.rmx2 = y.rmx2;
} else {
res.suf2 = suf2;
res.rmx2 = -y.sum + rmx2;
}
res.lp2 = suf2, res.rp2 = y.pre2;
res.val2 = rmx2 + y.lmx2;
if(res.val2 < val2)
res.val2 = val2, res.lp2 = lp2, res.rp2 = rp2;
if(res.val2 < y.val2)
res.val2 = y.val2, res.lp2 = y.lp2, res.rp2 = y.rp2;
return res;
}
}msg[N << 2];
struct Tag {
int tp;
inline void apply(Msg &t) const{
if(tp) {
t.sum = -t.sum;
swap(t.lmx1, t.lmx2), swap(t.rmx1, t.rmx2);
swap(t.pre1, t.pre2), swap(t.suf1, t.suf2);
swap(t.lp1, t.lp2), swap(t.rp1, t.rp2);
swap(t.val1, t.val2);
}
}
}tag[N << 2];
struct tri{
int a, b, c;
inline bool operator < (const tri y) {
return a < y.a;
}
};
inline tri max(tri x, tri y) {return y < x ? x : y;}
struct SegTree {
#define lc (k << 1)
#define rc (k << 1 | 1)
#define mid ((l + r) >> 1)
inline void pushdown(int k) {
tag[k].apply(msg[lc]), tag[k].apply(msg[rc]);
tag[lc].tp ^= tag[k].tp, tag[rc].tp ^= tag[k].tp;
tag[k].tp = 0;
}
inline void build(int k, int l, int r) {
if(l == r) {
tag[k] = (Tag){0};
if(a[l] < 0) tag[k] = (Tag){1}, a[l] = -a[l];
msg[k] = Msg{a[l], a[l], a[l], l, l, l, l, 0, 0, 0, l, l - 1, l - 1, l + 1, a[l]};
tag[k].apply(msg[k]);
return;
}
build(lc, l, mid), build(rc, mid + 1, r);
msg[k] = msg[lc] + msg[rc];
}
inline void modify(int k, int l, int r, int pos, int v) {
if(l > pos || r < pos) return;
if(l == r) {
tag[k].tp = 0;
if(v < 0) tag[k] = (Tag){1}, v = -v;
msg[k] = Msg{v, v, v, l, l, l, l, 0, 0, 0, l, l - 1, l - 1, l + 1, v};
tag[k].apply(msg[k]);
return;
}
pushdown(k);
modify(lc, l, mid, pos, v), modify(rc, mid + 1, r, pos, v);
msg[k] = msg[lc] + msg[rc];
}
inline void mul(int k, int l, int r, int L, int R) {
if(r < L || R < l) return;
if(L <= l && r <= R) {
Tag tmp{1};
tmp.apply(msg[k]);
tag[k].tp ^= -1;
return;
}
pushdown(k);
mul(lc, l, mid, L, R);
mul(rc, mid + 1, r, L, R);
msg[k] = msg[lc] + msg[rc];
}
inline Msg query(int k, int l, int r, int L, int R) {
if(r < L || R < l) return Msg{-inf, -inf, -inf, 0, 0, 0, 0, -inf, -inf, -inf, 0, 0, 0, 0, 0};
if(L <= l && r <= R) return msg[k];
pushdown(k);
return query(lc, l, mid, L, R) + query(rc, mid + 1, r, L, R);
}
}seg;
Msg stk[N];
int top;
signed main() {
read(n);
for(int i = 1; i <= n; ++i)
read(a[i]);
seg.build(1, 1, n);
int m = 0; read(m);
for(int i = 1, tp, x, y, z; i <= m; ++i) {
read(tp);
if(!tp) {
read(x), read(y);
seg.modify(1, 1, n, x, y);
}
else {
read(x), read(y), read(z);
int sum = 0;
while(z--) {
Msg res = seg.query(1, 1, n, x, y);
stk[++top] = res;
sum += res.val1;
seg.mul(1, 1, n, res.lp1, res.rp1);
}
printf("%lld\n",sum);
while(top) seg.mul(1, 1, n, stk[top].lp1, stk[top].rp1), --top;
}
}
return 0;
}
标签:int,res,Sum,Maximum,Subsequence,tag,msg,val2,sum
From: https://www.cnblogs.com/DCH233/p/17051734.html