BZOJ 3836 Codeforces 280D k-Maximum Subsequence Sum (模拟费用流、线段树)
题目链接
(BZOJ) https://www.lydsy.com/JudgeOnline/problem.php?id=3836
(Codeforces) http://codeforces.com/contest/280/problem/D
题解
似乎是最广为人知的模拟费用流题目。
线段树维护DP可以做,但是合并的复杂度是\(O(k^2)\), 会TLE.
考虑做\(k\)次费用流,很容易建出一个图,中间的边容量都是1,求的是最大费用。
做费用流的过程,我们每次找一条最长路,然后将其增广,增广之后这条路的边权会取负(因为容量都是\(1\)所以要么正要么负,正反向边不同时出现)。
所以现在要做的就是每次找出和最大的一段区间然后取负,直到和全都小于\(0\)为止。
线段树维护最大、最小子段和及其位置即可。
仔细想想,每次给一段区间取负就相当于给这段区间内的元素选或者不选的状态进行反转(inverse).
也就相当于费用流的退流(反悔)。
时间复杂度\(O(kn\log n)\).
代码
BZOJ权限号到期了,所以没在上面交过。
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<utility>
#include<vector>
#define pii pair<int,int>
#define mkpr make_pair
using namespace std;
void read(int &x)
{
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f;
}
const int N = 1e5;
int a[N+3];
vector<pii > pool;
int n,q;
struct Data
{
int sum,mx,mxl,mxr,pl,pr,pml,pmr;
Data() {sum = mx = mxl = mxr = pl = pr = pml = pmr = 0;}
};
Data operator +(Data x,Data y)
{
Data ret;
ret.sum = x.sum+y.sum;
if(x.mxl>x.sum+y.mxl)
{
ret.mxl = x.mxl;
ret.pl = x.pl;
}
else
{
ret.mxl = x.sum+y.mxl;
ret.pl = y.pl;
}
if(y.mxr>x.mxr+y.sum)
{
ret.mxr = y.mxr;
ret.pr = y.pr;
}
else
{
ret.mxr = x.mxr+y.sum;
ret.pr = x.pr;
}
if(x.mx>y.mx)
{
ret.mx = x.mx;
ret.pml = x.pml; ret.pmr = x.pmr;
}
else
{
ret.mx = y.mx;
ret.pml = y.pml; ret.pmr = y.pmr;
}
if(x.mxr+y.mxl>ret.mx)
{
ret.mx = x.mxr+y.mxl;
ret.pml = x.pr; ret.pmr = y.pl;
}
return ret;
}
struct SegmentTree
{
struct SgTNode
{
Data ans0,ans1; int tag;
} sgt[(N<<2)+3];
void pushup(int u)
{
sgt[u].ans0 = sgt[u<<1].ans0+sgt[u<<1|1].ans0;
sgt[u].ans1 = sgt[u<<1].ans1+sgt[u<<1|1].ans1;
}
void pushdown(int u)
{
if(sgt[u].tag)
{
swap(sgt[u<<1].ans0,sgt[u<<1].ans1);
sgt[u<<1].tag ^= 1;
swap(sgt[u<<1|1].ans0,sgt[u<<1|1].ans1);
sgt[u<<1|1].tag ^= 1;
sgt[u].tag = 0;
}
}
void build(int u,int le,int ri)
{
if(le==ri)
{
sgt[u].ans0.sum = sgt[u].ans0.mxl = sgt[u].ans0.mxr = sgt[u].ans0.mx = a[le];
sgt[u].ans0.pl = sgt[u].ans0.pr = sgt[u].ans0.pml = sgt[u].ans0.pmr = le;
sgt[u].ans1.sum = sgt[u].ans1.mxl = sgt[u].ans1.mxr = sgt[u].ans1.mx = -a[le];
sgt[u].ans1.pl = sgt[u].ans1.pr = sgt[u].ans1.pml = sgt[u].ans1.pmr = le;
return;
}
int mid = (le+ri)>>1;
build(u<<1,le,mid);
build(u<<1|1,mid+1,ri);
pushup(u);
}
void modify(int u,int le,int ri,int pos,int x)
{
if(le==pos && ri==pos)
{
sgt[u].ans0.sum = sgt[u].ans0.mxl = sgt[u].ans0.mxr = sgt[u].ans0.mx = x;
sgt[u].ans0.pl = sgt[u].ans0.pr = sgt[u].ans0.pml = sgt[u].ans0.pmr = le;
sgt[u].ans1.sum = sgt[u].ans1.mxl = sgt[u].ans1.mxr = sgt[u].ans1.mx = -x;
sgt[u].ans1.pl = sgt[u].ans1.pr = sgt[u].ans1.pml = sgt[u].ans1.pmr = le;
return;
}
pushdown(u);
int mid = (le+ri)>>1;
if(pos<=mid) modify(u<<1,le,mid,pos,x);
if(pos>mid) modify(u<<1|1,mid+1,ri,pos,x);
pushup(u);
}
void setoppo(int u,int le,int ri,int lb,int rb)
{
if(le>=lb && ri<=rb)
{
sgt[u].tag ^= 1;
swap(sgt[u].ans0,sgt[u].ans1);
return;
}
pushdown(u);
int mid = (le+ri)>>1;
if(lb<=mid) setoppo(u<<1,le,mid,lb,rb);
if(rb>mid) setoppo(u<<1|1,mid+1,ri,lb,rb);
pushup(u);
}
Data query(int u,int le,int ri,int lb,int rb)
{
if(le>=lb && ri<=rb) {return sgt[u].ans0;}
pushdown(u);
int mid = (le+ri)>>1; Data ret;
if(rb<=mid) {ret = query(u<<1,le,mid,lb,rb);}
else if(lb>mid) {ret = query(u<<1|1,mid+1,ri,lb,rb);}
else {ret = query(u<<1,le,mid,lb,rb)+query(u<<1|1,mid+1,ri,lb,rb);}
pushup(u);
return ret;
}
} sgt;
int main()
{
scanf("%d",&n);
for(int i=1; i<=n; i++) scanf("%d",&a[i]);
sgt.build(1,1,n);
scanf("%d",&q);
while(q--)
{
int opt; scanf("%d",&opt);
if(opt==0)
{
int x,y; scanf("%d%d",&x,&y);
a[x] = y; sgt.modify(1,1,n,x,y);
}
else if(opt==1)
{
int x,y,z; scanf("%d%d%d",&x,&y,&z);
int ans = 0;
for(int i=1; i<=z; i++)
{
Data cur = sgt.query(1,1,n,x,y);
// printf("delta=%d [%d,%d]\n",cur.mx,cur.pml,cur.pmr);
if(cur.mx<=0) break;
ans += cur.mx;
sgt.setoppo(1,1,n,cur.pml,cur.pmr);
pool.push_back(mkpr(cur.pml,cur.pmr));
}
printf("%d\n",ans);
for(int i=0; i<pool.size(); i++) {sgt.setoppo(1,1,n,pool[i].first,pool[i].second);}
pool.clear();
}
}
return 0;
}
BZOJ 3836 Codeforces 280D k-Maximum Subsequence Sum (模拟费用流、线段树)的更多相关文章
- 【bzoj3638】Cf172 k-Maximum Subsequence Sum 模拟费用流+线段树区间合并
题目描述 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交的不超过k个子段,最大的和是多少. 输入 The first line contains inte ...
- BZOJ.3638.CF172 k-Maximum Subsequence Sum(模拟费用流 线段树)
题目链接 各种zz错误..简直了 /* 19604kb 36292ms 题意:选$k$段不相交的区间,使其权值和最大. 朴素线段树:线段树上每个点维护O(k)个信息,区间合并时O(k^2),总O(mk ...
- Codeforces 280D k-Maximum Subsequence Sum [模拟费用流,线段树]
洛谷 Codeforces bzoj1,bzoj2 这可真是一道n倍经验题呢-- 思路 我首先想到了DP,然后矩阵,然后线段树,然后T飞-- 搜了题解之后发现是模拟费用流. 直接维护选k个子段时的最优 ...
- BZOJ3638[Codeforces280D]k-Maximum Subsequence Sum&BZOJ3272Zgg吃东西&BZOJ3267KC采花——模拟费用流+线段树
题目描述 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交的不超过k个子段,最大的和是多少. 输入 The first line contains inte ...
- CF280D-k-Maximum Subsequence Sum【模拟费用流,线段树】
正题 题目链接:https://www.luogu.com.cn/problem/CF280D 题目大意 一个长度为\(n\)的序列,\(m\)次操作 修改一个数 询问一个区间中选出\(k\)段不交子 ...
- BZOJ 4276 [ONTAK2015]Bajtman i Okrągły Robin 费用流+线段树优化建图
Description 有n个强盗,其中第i个强盗会在[a[i],a[i]+1],[a[i]+1,a[i]+2],...,[b[i]-1,b[i]]这么多段长度为1时间中选出一个时间进行抢劫,并计划抢 ...
- Maximum Subsequence Sum【最大连续子序列+树状数组解决】
Problem Description 给定K个整数的序列{ N1, N2, ..., NK },其任意连续子序列可表示为{ Ni, Ni+1, ..., Nj },其中 1 <= i < ...
- 中国大学MOOC-陈越、何钦铭-数据结构-2015秋 01-复杂度2 Maximum Subsequence Sum (25分)
01-复杂度2 Maximum Subsequence Sum (25分) Given a sequence of K integers { N1,N2, ..., NK }. ...
- PAT1007:Maximum Subsequence Sum
1007. Maximum Subsequence Sum (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Y ...
随机推荐
- Python基础字符串前加u,r,b,f含义
1.字符串前加 u 例:u"我是含有中文字符组成的字符串." 作用: 后面字符串以 Unicode 格式 进行编码,一般用在中文字符串前面,防止因为源码储存格式问题,导致再次使用时 ...
- Mysql学习(一)之简单介绍
数据库简介 数据库分类 关系型数据库:MySQL.Oracle.SQLServer.Access.db2.fox pro 文件型数据库:sqlite.mongodb 空间型数据库: 数据库分为两端 数 ...
- 浅尝https
HTTPS http超文本传输协议,所以的东西都是明文传输,容易被拦截,被攻击,我们希望能对通话内容进行加密,那么因此而生,出现了https https:在http的基础上新增加了SSL层 先放图 / ...
- 本地存储cookie,localStorage,sessionStorage
常见的前端存储有老朋友 cookie,短暂的 sessionStorage,和简单强大的localStorage 他们之间的区别有以下几点 1.. cookie在浏览器和服务器间来回传递.而sessi ...
- ZeroMQ 三种模式python3实现
ZeroMQ是一个消息队列网络库,实现网络常用技术封装.在C/S中实现了三种模式,这段时间用python简单实现了一下,感觉python虽然灵活.但是数据处理不如C++自由灵活. Request-Re ...
- TP-Link 路由器 如何在现有的环境中改善无线信号传输质量
http://service.tp-link.com.cn/detail_article_346.html
- Linux使用Docker启动Elasticsearch并配合Kibana使用,安装ik分词器
注意事项 这里我的Linux虚拟机的IP地址是192.168.1.3 Docker运行Elasticsearch容器之后不会立即有反应,要等一会,等待容器内部启动Elasticsearch,才可以访问 ...
- Elasticsearch中文文档,内容不全
注意 内容不全,这是观看中文文档进行操作的 文档地址 旧版中文文档,部分内容过期 https://www.elastic.co/guide/cn/elasticsearch/guide/current ...
- Hbase1.4.9的安装
HBase介绍 HBase – Hadoop Database,是一个高可靠性.高性能.面向列.可伸缩的分布式存储系统,利用HBase技术可在廉价PC Server上搭建起大规模结构化存储集群. HB ...
- 微信小程序获得高度
wx.getSystemInfo({ success: (res) => { wx.createSelectorQuery().select('#scrollbox').boundingClie ...