昨天考试被教育了一波。为了学习一下\(T3\)的科技,我就找到了这个远古时期的\(cf\)题(虽然最后\(T3\)还是不会写吧\(QAQ\))

顾名思义,这个题目其实可以建成一个费用流的模型。我们用流量来限制区间个数,用费用强迫它每次每次选择最大的区间就可以啦。但是因为询问很多,复杂度似乎不行,于是就有了这种神奇的科技——线段树模拟费用流。

在原先的费用流模型里,我们有正反两种边,而反向边的意义就在于,在每一次增广的时候可以反悔以前的操作,把局部最优向更大范围的局部更优优化。

参考反向边的原理,我们可以想象出来:如果对这个区间,我们每次都取用最大子区间,并在取用这个最大子区间以后将其价值变为负数,不就可以模拟费用流的行为了嘛?这样做的复杂度是\(O(NMlogN)\)的,可以解决更大数据范围的问题。

算法很好理解,关键是千万不要把代码写挂\(QwQ\),真的不是很好调啊\(TwT\)


#include<bits/stdc++.h>
using namespace std; struct dat {
int s; //sum of sequence
int lmx, lmxp; //left -> max_val && it's pos
int lmn, lmnp; //left -> min_val && it's pos
int rmx, rmxp; //righ -> max_val && it's pos
int rmn, rmnp; //righ -> min_val && it's pos
int smx, smxl, smxr; //sub -> max_val && it's pos (l, r)
int smn, smnl, smnr; //sub -> min_val && it's pos (l, r)
dat (int pos = 0, int val = 0){
lmxp = lmnp = rmxp = rmnp = smxl = smxr = smnl = smnr = pos;
s = lmx = lmn = rmx = rmn = smx = smn = val;
//对单个的点进行数据更新
}
}T[400010]; dat operator + (dat l, dat r){
dat u;
u.s = l.s+r.s; //先更新关于和的数据
if (l.lmx > l.s + r.lmx) { //max_left's pos 是否越过 mid
u.lmx = l.lmx;
u.lmxp = l.lmxp;
} else {
u.lmx = l.s + r.lmx;
u.lmxp = r.lmxp;
}
if (r.rmx > r.s + l.rmx) { //max_righ's pos 是否越过 mid
u.rmx = r.rmx;
u.rmxp = r.rmxp;
} else {
u.rmx = r.s + l.rmx;
u.rmxp = l.rmxp;
}
if (l.lmn < l.s + r.lmn) { //min_left's pos 是否越过 mid
u.lmn = l.lmn;
u.lmnp = l.lmnp;
} else {
u.lmn = l.s + r.lmn;
u.lmnp = r.lmnp;
}
if (r.rmn < r.s + l.rmn) { //min_righ's pos 是否越过 mid
u.rmn = r.rmn;
u.rmnp = r.rmnp;
} else {
u.rmn = r.s + l.rmn;
u.rmnp = l.rmnp;
}
if (l.smx > r.smx) { //最大子段 in left / righ
u.smx = l.smx;
u.smxl = l.smxl;
u.smxr = l.smxr;
} else {
u.smx = r.smx;
u.smxl = r.smxl;
u.smxr = r.smxr;
}
if (l.rmx + r.lmx > u.smx){ //最大子段是否越过 mid
u.smx = l.rmx + r.lmx;
u.smxl = l.rmxp;
u.smxr = r.lmxp;
}
if (l.smn < r.smn) { //最小子段 in left / righ
u.smn = l.smn;
u.smnl = l.smnl;
u.smnr = l.smnr;
} else {
u.smn = r.smn;
u.smnl = r.smnl;
u.smnr = r.smnr;
}
if (l.rmn + r.lmn < u.smn) { //最小子段是否跨过 mid
u.smn = l.rmn + r.lmn;
u.smnl = l.rmnp;
u.smnr = r.lmnp;
}
return u;
} #define ls (x << 1)
#define rs (x << 1 | 1) void pushup (int x) {
T[x] = T[ls] + T[rs];
} int a[100010]; void build (int l, int r, int x) {
if (l == r) {
T[x] = dat (l, a[l]);
return;
}
int mid = (l + r) >> 1;
build (l, mid, ls);
build (mid + 1, r, rs);
pushup (x);
} int f[400010]; void rev (int x) {
dat &u = T[x];
// max 变成 min
swap (u.lmx, u.lmn);
swap (u.lmxp, u.lmnp);
swap (u.rmx, u.rmn);
swap (u.rmxp, u.rmnp);
swap (u.smx, u.smn);
swap (u.smxl, u.smnl);
swap (u.smxr, u.smnr);
f[x] ^= 1;
u.lmx *= -1;
u.lmn *= -1;
u.rmx *= -1;
u.rmn *= -1;
u.smx *= -1;
u.smn *= -1;
u.s *= -1;
}
void pushdown (int x) {
if(f[x]) {
rev (ls);
rev (rs);
f[x] = 0;
}
} void modify (int p, int v, int l, int r, int x) {
if (l == r) {
T[x] = dat (l, v);
return;
}
pushdown (x);
int mid = (l + r) >> 1;
if (p <= mid) {
modify (p, v, l, mid, ls);
} else {
modify (p, v, mid + 1, r, rs);
}
pushup (x);
} void reverse (int L, int R, int l, int r, int x) {
//其实就是取用啦
if (L <= l && r <= R) return rev (x);
pushdown (x);
int mid = (l + r) >> 1;
if (L <= mid) reverse (L, R, l, mid, ls);
if (mid < R) reverse (L, R, mid + 1, r, rs);
pushup (x);
} dat query (int L, int R, int l, int r, int x) {
//求[l, r]区间内的最大值嘛
if (L <= l && r <= R) return T[x];
pushdown (x);
int mid = (l + r) >> 1;
if (R <= mid) return query (L, R, l, mid, ls); //如果区间全在左边
if (mid < L) return query (L, R, mid + 1, r, rs); //如果区间全在右边
return query (L, R, l, mid, ls) + query (L, R, mid + 1, r, rs); //跨 mid 了 QwQ
} int L[30], R[30], top;
int n, m, x, y, k, opt; int main () {
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
}
build (1, n, 1);
cin >> m;
for (int i = 1; i <= m; ++i) {
cin >> opt >> x >> y;
if (opt == 0) {
modify (x, y, 1, n, 1); //把点 x 的值改为 y
} else {
cin >> k; //在[x, y]之间取 k 段的最大值
int ans = 0;
for (int j = 1; j <= k; ++j) {
dat t = query (x, y, 1, n, 1);
if (t.smx <= 0) break;
//选至多 k 段, 可以少选 !
ans += t.smx;
L[++top] = t.smxl, R[top] = t.smxr;
reverse (L[top], R[top], 1, n, 1);
}
while (top) {
reverse (L[top], R[top], 1, n, 1);
top = top - 1;
}
cout << ans << endl;
}
}
}

【CF280D】 k-Maximum Subsequence Sum ,线段树模拟费用流的更多相关文章

  1. [BZOJ3638 && BZOJ3272]带修区间不相交最大K子段和(线段树模拟费用流)

    https://www.cnblogs.com/DaD3zZ-Beyonder/p/5634149.html k可重区间集问题有两种建图方式,可能这一种才可以被线段树优化. 换个角度看,这也是一个类似 ...

  2. 【BZOJ3638】Cf172 k-Maximum Subsequence Sum 线段树区间合并(模拟费用流)

    [BZOJ3638]Cf172 k-Maximum Subsequence Sum Description 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交 ...

  3. CF280D k-Maximum Subsequence Sum(线段树)

    在做这题时我一开始把\(tag\)写入了结构体 #include <iostream> #include <cstdio> #include <cstring> # ...

  4. 【bzoj3638】Cf172 k-Maximum Subsequence Sum 模拟费用流+线段树区间合并

    题目描述 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交的不超过k个子段,最大的和是多少. 输入 The first line contains inte ...

  5. Codeforces 280D k-Maximum Subsequence Sum [模拟费用流,线段树]

    洛谷 Codeforces bzoj1,bzoj2 这可真是一道n倍经验题呢-- 思路 我首先想到了DP,然后矩阵,然后线段树,然后T飞-- 搜了题解之后发现是模拟费用流. 直接维护选k个子段时的最优 ...

  6. BZOJ 3836 Codeforces 280D k-Maximum Subsequence Sum (模拟费用流、线段树)

    题目链接 (BZOJ) https://www.lydsy.com/JudgeOnline/problem.php?id=3836 (Codeforces) http://codeforces.com ...

  7. BZOJ 5326 [JSOI2017]博弈 (模拟费用流、线段树)

    题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=5326 题解 终于成为第8个A掉这题的人--orz tzw神仙早我6小时 本以为这东西常数 ...

  8. 1007 Maximum Subsequence Sum (25分) 求最大连续区间和

    1007 Maximum Subsequence Sum (25分)   Given a sequence of K integers { N​1​​, N​2​​, ..., N​K​​ }. A ...

  9. 中国大学MOOC-陈越、何钦铭-数据结构-2015秋 01-复杂度2 Maximum Subsequence Sum (25分)

    01-复杂度2 Maximum Subsequence Sum   (25分) Given a sequence of K integers { N​1​​,N​2​​, ..., N​K​​ }. ...

随机推荐

  1. 由 POST 400 错误拔出来的萝卜

    缘起 前段时间遇到扫描问题,好不容易拿到了扫描出来的数据,结果调用接口时弹了个 400(Bad request) 给我,匆匆找了点资料修补上线后,忐忑的心也可以安分点.然后,顺着这个 400 的萝卜, ...

  2. 学习 Spring (九) 注解之 @Required, @Autowired, @Qualifier

    Spring入门篇 学习笔记 @Required @Required 注解适用于 bean 属性的 setter 方法 这个注解仅仅表示,受影响的 bean 属性必须在配置时被填充,通过在 bean ...

  3. Web API 2 使用SSL

    在Server上启用SSL 稍后我会想在IIS 7 上配置SSL,现在先往下看. 本地测试,您可以启用SSL的IIS Express Visual Studio.在属性窗口中,启用SSL设置为True ...

  4. hdu-2255(带权二分图)

    题解:板子题.... #include<iostream> #include<cstring> #include<cstdio> #include<queue ...

  5. hdu-2717(基础搜索bfs)

    题意:给你n和k,问你n最少花费多少代价能得到k: 有两种变换:1.n++或者n--: 2.n=n*2: 两种代价每次的花费都是1: 思路:一维的bfs,每次入队三个点,一个是n+1,一个是n-1,一 ...

  6. Keepalived+LVS高可用负载均衡集群

    概述 Keepalived是专门针对LVS设计的一款强大的辅助工具,主要用来提供故障切换(Failover)和健康检查(HeathChecking)功能——判断LVS负载调度器.节点服务器的可用性,及 ...

  7. MySQL数据库实现分页查询的SQL语句写法!

    一:分页需求: 客户端通过传递start(页码),limit(每页显示的条数)两个参数去分页查询数据库表中的数据,那我们知道MySql数据库提供了分页的函数limit m,n,但是该函数的用法和我们的 ...

  8. 【XSY1580】Y队列 容斥

    题目大意 给你\(n,r\),求第\(n\)个不能被表示为\(a^b(2\leq b\leq r)\)的数 \(n\leq 2\times {10}^{18},r\leq 62\) 题解 我们考虑二分 ...

  9. Fiddler中显示IP方法

    如何在fiddler查看到请求的IP地址?就像下面这样 打开fiddler, 快捷键Ctrl+R  或者  菜单->Rules->Customize Rules…,然后在CustomRul ...

  10. [2017-7-27]Android Learning Day5

    总结篇! 吭哧吭哧了三天,最近不断研究<第一行代码:第二版>170多页的那个新闻实践项目,虽然也没有用到数据库和一些Web爬虫的知识,新闻数据都是随机生成的字符串...... 但还是很开心 ...