费用流+线段树

看见这个题我们马上就能想到费用流,设立源汇,分别向每个点连接容量为1费用为0的边,然后相邻的点之间连边,费用为点权,跑费用流就行了,但是很明显这样会超时,那么我们要优化一下,我们观察费用流的过程,发现对于点与点之间的边,每次取一段区间相当于把正向边改为反向边,费用变负,于是我们可以用线段树来模拟这个过程,像费用流一样贪心地选取区间的最大子段和,然后取反,每次取k次,然后恢复。这样就好了

但是写的时候有很多问题,比如如何返回一个区间?结构体!参考了popoqqq大神的代码,发现我们可以通过重载小于号直接对结构体取max,这样就十分好写了

然后这道题有点卡常,一定要在重载的时候把传入参数变成const+引用,这样在cf上快了200ms

这就是传说中的五倍经验吗

#include<bits/stdc++.h>
using namespace std;
const int N = ;
namespace IO
{
const int Maxlen = N * ;
char buf[Maxlen], *C = buf;
int Len;
inline void read_in()
{
Len = fread(C, , Maxlen, stdin);
buf[Len] = '\0';
}
inline void fread(int &x)
{
x = ;
int f = ;
while (*C < '' || '' < *C) { if(*C == '-') f = -; ++C; }
while ('' <= *C && *C <= '') x = (x << ) + (x << ) + *C - '', ++C;
x *= f;
}
inline void read(int &x)
{
x = ;
int f = ; char c = getchar();
while(c < '' || c > '') { if(c == '-') f = -; c = getchar(); }
while(c >= '' && c <= '') { x = (x << ) + (x << ) + c - ''; c = getchar(); }
x *= f;
}
inline void read(long long &x)
{
x = ;
long long f = ; char c = getchar();
while(c < '' || c > '') { if(c == '-') f = -; c = getchar(); }
while(c >= '' && c <= '') { x = (x << 1ll) + (x << 3ll) + c - ''; c = getchar(); }
x *= f;
}
} using namespace IO;
struct data {
int l, r, v;
data() {}
data(int l, int r, int v) : l(l), r(r), v(v) {}
friend bool operator < (const data &a, const data &b) { return a.v < b.v; }
friend data operator + (const data &a, const data &b) { return data(a.l, b.r, a.v + b.v); }
};
struct node {
data lmax, rmax, mx, mn, lmin, rmin, sum;
int tag;
node() {}
node(int x, int v) {
lmax = rmax = mx = mn = lmin = rmin = sum = data(x, x, v);
}
friend node operator + (const node &a, const node &b) {
node c;
if(a.tag == -) return b;
if(b.tag == -) return a;
c.tag = ;
c.sum = a.sum + b.sum;
c.lmax = max(a.lmax, a.sum + b.lmax);
c.lmin = min(a.lmin, a.sum + b.lmin);
c.rmax = max(b.rmax, a.rmax + b.sum);
c.rmin = min(b.rmin, a.rmin + b.sum);
c.mx = max(max(a.mx, b.mx), a.rmax + b.lmax);
c.mn = min(min(a.mn, b.mn), a.rmin + b.lmin);
return c;
}
} tree[N << ], st[];
int n, q;
int a[N];
void paint(node &o)
{
swap(o.lmax, o.lmin);
swap(o.rmax, o.rmin);
swap(o.mx, o.mn);
o.sum.v *= -;
o.lmax.v *= -;
o.lmin.v *= -;
o.rmax.v *= -;
o.rmin.v *= -;
o.mx.v *= -;
o.mn.v *= -;
o.tag ^= ;
}
void pushdown(int x)
{
if(tree[x].tag <= ) return;
paint(tree[x << ]);
paint(tree[x << | ]);
tree[x].tag ^= ;
}
void build(int l, int r, int x)
{
if(l == r)
{
tree[x] = node(l, a[l]);
return;
}
int mid = (l + r) >> ;
build(l, mid, x << );
build(mid + , r, x << | );
tree[x] = tree[x << ] + tree[x << | ];
}
node query(int l, int r, int x, int a, int b)
{
if(l > b || r < a) return tree[];
if(l >= a && r <= b) return tree[x];
pushdown(x);
int mid = (l + r) >> ;
return (query(l, mid, x << , a, b)) + (query(mid + , r, x << | , a, b));
}
void reverse(int l, int r, int x, int a, int b)
{
if(l > b || r < a) return;
if(l >= a && r <= b)
{
paint(tree[x]);
return;
}
pushdown(x);
int mid = (l + r) >> ;
reverse(l, mid, x << , a, b);
reverse(mid + , r, x << | , a, b);
tree[x] = tree[x << ] + tree[x << | ];
}
void update(int l, int r, int x, int pos, int v)
{
if(l == r)
{
tree[x] = node(l, v);
return;
}
pushdown(x);
int mid = (l + r) >> ;
if(pos <= mid) update(l, mid, x << , pos, v);
else update(mid + , r, x << | , pos, v);
tree[x] = tree[x << ] + tree[x << | ];
}
int main()
{
read_in();
fread(n);
for(int i = ; i <= n; ++i) fread(a[i]);
tree[].tag = -;
build(, n, );
fread(q);
while(q--)
{
int opt, l, r, v;
fread(opt);
if(opt == )
{
fread(l);
fread(v);
update(, n, , l, v);
}
if(opt == )
{
fread(l);
fread(r);
fread(v);
int sum = , top = ;
while(v--)
{
node ans = query(, n, , l, r);
if(ans.mx.v <= ) break;
reverse(, n, , ans.mx.l, ans.mx.r);
node tmp = query(, n, , ans.mx.l, ans.mx.r);
st[++top] = ans;
sum += ans.mx.v;
}
printf("%d\n", sum);
for(int i = top; i; --i) reverse(, n, , st[i].mx.l, st[i].mx.r);
}
}
return ;
}

bzoj3638的更多相关文章

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

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

  2. 【BZOJ-3638&3272&3267&3502】k-Maximum Subsequence Sum 费用流构图 + 线段树手动增广

    3638: Cf172 k-Maximum Subsequence Sum Time Limit: 50 Sec  Memory Limit: 256 MBSubmit: 174  Solved: 9 ...

  3. BZOJ3638[Codeforces280D]k-Maximum Subsequence Sum&BZOJ3272Zgg吃东西&BZOJ3267KC采花——模拟费用流+线段树

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

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

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

  5. BZOJ3638|CodeForces 280D k-Maximum Subsequence Sum

    题目链接:戳我 一类典型模型.线段树模拟网络流+区间最大K段和. 因为不会写,所以参考了黄学长的博客.但是我觉得他说得不够详细,所以想好好地解释一下: 前置技能1:区间最大子段和 如果K=1的时候怎么 ...

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

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

  7. bzoj3638 Cf172 k-Maximum Subsequence Sum

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3638 [题解] 看到k<=20就感觉很py了啊 我们用一棵线段树维护选段的过程,能选到 ...

  8. [转载]hzwer的bzoj题单

    counter: 664BZOJ1601 BZOJ1003 BZOJ1002 BZOJ1192 BZOJ1303 BZOJ1270 BZOJ3039 BZOJ1191 BZOJ1059 BZOJ120 ...

  9. BZOJ刷题列表【转载于hzwer】

    沿着黄学长的步伐~~ 红色为已刷,黑色为未刷,看我多久能搞完吧... Update on 7.26 :之前咕了好久...(足见博主的flag是多么emmm......)这几天开始会抽时间刷的,每天几道 ...

随机推荐

  1. Eval 和 Bind 的区别

    原文发布时间为:2008-10-20 -- 来源于本人的百度文章 [由搬家工具导入] 据绑定表达式包含在 <%# 和 %> 分隔符之内,并使用 Eval 和 Bind 函数。 Eval 函 ...

  2. PB编译

    java -jar wire-compiler-1.8.0-jar-with-dependencies.jar --java_out=./  ngame.proto 其中java_out是指输出要放在 ...

  3. 16 个常用的yum 命令

    1. yum [-y] install package_name2. yum remove package_name                                  卸载指定软件3. ...

  4. 第18章:MYSQL分区

    第18章:分区 目录 18.1. MySQL中的分区概述 18.2. 分区类型 18.2.1. RANGE分区 18.2.2. LIST分区 18.2.3. HASH分区 18.2.4. KEY分区 ...

  5. codechef FUN WITH TREES

    题目大意: 给一棵树root=1的树: 给一些操作:u  v 的路径所有节点的node + val: 最后m个询问:u 节点(包括u) sum%mod 是多少. LCA + RMQ: 我们每次mark ...

  6. Codeforces 920G(二分+容斥)

    题意: 定义F(x,p)表示的是一个数列{y},其中gcd(y,p)=1且y>x 给出x,p,k,求出F(x,p)的第k项 x,p,k<=10^6 分析: 很容易想到先二分,再做差 然后问 ...

  7. java 数组 输入5名学生的成绩 得出平均分。

    import java.util.Scanner; public class LianXi4{ public static void main(String[] args){ //创建长度为5的数组 ...

  8. 通过简单的两数相加体会hashmap的好处

    目录 引入题目:两数相加 HashMap相关知识: Map集合 Map集合的特点 Map常用子类 HashMap集合 LinkedHashMap集合 Map集合的常用方法 Map集合的第一种遍历方式: ...

  9. 关于oracle存储过程的若干问题备忘

    1.在oracle中,数据表别名不能加as,如: select a.appname from appinfo a;-- 正确select a.appname from appinfo as a;-- ...

  10. httpclient请求去掉返回结果string中的多余转义字符

    public String doGet() { String uriAPI = "http://XXXXX?str=I+am+get+String"; String result= ...