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 ...
随机推荐
- C语言&*符号使用及大端法小端法测试
工具:Microsoft Visual C++ 6.0 例子: int a = 1; int* b = &a; C语言规定a表示存储单元中的数据,&a表示存储单元的地址,b存储的就是a ...
- c++学习之对象和类——构造函数和析构函数
再认真理一遍~ 0.类 这里先来定义一个类,便于后面的理解.参考C++ Primer Plus class Stock { private: std::string company; long sha ...
- 从入门到自闭之Python时间模块
time模块:import time time.time():时间戳,是一个浮点数,按秒来计算 time.sleep():睡眠,程序暂停多少秒执行 python中时间日期格式化符号: 必背 %y 两位 ...
- jinja2 模板相关
安装 pip install jinja2 配置模板 settings.py 60行左右 TEMPLATES = [ { 'BACKEND': 'django.template.backends.dj ...
- CVE-2018-19985漏洞学习
简介 4.19.8之前,在Linux内核中,hso_probe()函数中发现了一个缺陷,该函数从USB设备(作为u8)读取if_num值,并且不需要对数组进行长度检查就使用它来索引数组,从而导致在hs ...
- Box-shadow制作漂亮的外阴影输入框
背景:之前做项目中的一个移动端页面,关于在搜索框中输入信息查找对应的照片 改了几次ui图之后,最终的搜索框的设计图如下: 开始做页面的时候,就想到了用box-shadow 来实现外阴影边框.用bord ...
- O020、理解 Glance
参考https://www.cnblogs.com/CloudMan6/p/5384923.html OpenStack 由 Glance 提供 Image 服务. 理解 Glance ...
- 关于IDEA的application.properties读取乱码,以及显示乱码问题
设置编码 如果设置之后还是不成功,就重启IDEA 再不行就删除application.properties重新编辑, 我采用的是注释掉要读取的中文部分,再下面再写一行
- Ubuntu中用bitbake core-image-minimal时,出错:from bb import data
问题描述: 在准备ARM交叉编译环境时,执行完命令: DISTRO=fsl-imx-x11 MACHINE=imx6qsabresd source fsl-setup-release.sh -b bu ...
- 利用nethogs查看哪些进程占用网络带宽
一.安装nethogs centos6版本安装: 1.安装依赖包 [root@hlsms-fensheng- ~]# yum install ncurses* 已加载插件:fastestmirror, ...