LOJ#3097 [SNOI2019]通信 最小费用最大流+cdq分治/主席树/分块优化建图
瞎扯
我们网络流模拟赛(其实是数据结构模拟赛)的T2。
考场上写主席树写自闭了,直接交了\(80pts\)的暴力,考完出来突然发现:
- woc这个题一个cdq几行就搞定了!
题意简述
有\(n\)个哨站,第\(i\)个哨站的频段为\(a_i\)。每个哨站可以花费\(W\)连接中心,也可以花费\(|a_j-a_i|\)连接到第\(j\)个哨站(\(j<i\))。
每个哨站最多只能被连接一次,求所有哨站连接的最小花费。
做法
Luogu能过的暴力
由最多只能被连接一次想到流量限制(显然),发现题目要求最小花费,所以建图跑最小费用最大流。
考虑暴力建边,将每个点拆成\(2\)个点,一个表示直接连接中心,另一个限制流量。
- 所以有\(S \xrightarrow{1/0} i \xrightarrow{1/W} T\),\(i \xrightarrow{\infty/|a_i-a_j|} j'\),\(i' \xrightarrow{1/0} T\)。
考场上我写完建图和zkw费用流就跑了,然后突然发现边是\(n^2\)的,跑极限数据要跑\(100s+\),但是我后面交luogu竟然过了???
暴力代码
// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register int
#define db double
#define in inline
namespace fast_io
{
char buf[1<<12],*p1=buf,*p2=buf,sr[1<<23],z[23],nc;int C=-1,Z=0;
in char gc() {return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<12,stdin),p1==p2)?EOF:*p1++;}
in ll read()
{
ll x=0,y=1;while(nc=gc(),(nc<48||nc>57)&&nc!=-1) if(nc==45) y=-1;
x=nc-48;while(nc=gc(),47<nc&&nc<58) x=(x<<3)+(x<<1)+(nc^48);return x*y;
}
in db gf() {re a=read(),b=(nc!='.')?0:read(),c=ceil(log10(b));return (b?a+(db)b/pow(10,c):a);}
in int gs(char *s) {char c,*t=s;while(c=gc(),c<32);*s++=c;while(c=gc(),c>32)*s++=c;return s-t;}
template <typename T>
in void write(T x,char t)
{
re y=0;if(x<0) y=1,x=-x;while(z[++Z]=x%10+48,x/=10);
if(y) z[++Z]='-';while(sr[++C]=z[Z],--Z);sr[++C]=t;
}
in void write(char *s) {re l=strlen(s);for(re i=0;i<l;i++,*s++)sr[++C]=*s;sr[++C]='\n';}
in void ot() {fwrite(sr,1,C+1,stdout);C=-1;}
};
using namespace fast_io;
const int N=2e3+5;
const ll inf=1e18;
int cnt=1,sum,tot,n,s,t,m,k;
int h[N],l,r,q[N],vis[N],a[N];
ll ans,maxflow,dis[N];
struct did{int u,next,to,f,w;}e[N*N];
in void add(re a,re b,re c,re d)
{
e[++cnt]=(did){a,h[a],b,c,d},h[a]=cnt;
e[++cnt]=(did){b,h[b],a,0,-d},h[b]=cnt;
}
int spfa()
{
memset(vis,0,sizeof(vis));
for(re i=s;i<=t;i++) dis[i]=i==s?0:inf;
queue<int>q;q.push(s);vis[s]=1;
while(!q.empty())
{
re i=q.front();vis[i]=0;q.pop();
for(re j=h[i],k;k=e[j].to,j;j=e[j].next)
if(e[j].f&&dis[k]>dis[i]+e[j].w)
{
dis[k]=dis[i]+e[j].w;
if(!vis[k]) q.push(k),vis[k]=1;
}
}
return dis[t]<inf;
}
in int dfs(re u,re f)
{
if(u==t) return f; vis[u]=1;
re res=0;
for(re i=h[u],v;v=e[i].to,i&&res<f;i=e[i].next)
if(e[i].f&&!vis[v]&&dis[v]==dis[u]+e[i].w)
{
re t=dfs(v,min(f-res,e[i].f));
res+=t;ans+=(ll)e[i].w*t;
e[i].f-=t;e[i^1].f+=t;
}
if(!res) dis[u]=inf;
return vis[u]=0,res;
}
in void zkw() {while(spfa()) memset(vis,0,sizeof(vis)),maxflow+=dfs(s,1e9);}
int main()
{
n=read();m=read();s=0,t=n*2+1;
for(re i=1;i<=n;i++) a[i]=read(),add(s,i,1,0),add(i,t,1,m),add(n+i,t,1,0);
for(re i=1;i<n;i++) for(re j=i+1;j<=n;j++)
if(abs(a[i]-a[j])<m) add(j,n+i,1,abs(a[i]-a[j]));
zkw();write(ans,'\n');
return ot(),0;
}
正解(暴力优化)
发现本题瓶颈在于一个点向一个区间连边,而且有费用。
考场上没想到可以转化负数,一直不知道如何解决绝对值。这里采用常数和花费更为优秀的cdq分治,分治后将区间内所有的虚点间连接费用为\(\Delta a\)的边,二分保证连边的\(a_j\)都大于\(a_i\)即可。
Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register int
#define db double
#define in inline
namespace fast_io
{
char buf[1<<12],*p1=buf,*p2=buf,sr[1<<23],z[23];int C=-1,Z=0;
in char gc() {return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<12,stdin),p1==p2)?EOF:*p1++;}
in ll read()
{
ll x=0,y=1;char c;while(c=gc(),(c<48||c>57)&&c!=-1) if(c==45) y=-1;
x=c-48;while(c=gc(),47<c&&c<58) x=(x<<3)+(x<<1)+(c^48);return x*y;
}
in db gf() {int a=read(),b=read(),c=ceil(log10(b));return (b?a+(db)b/pow(10,c):a);}
in int gs(char *s) {char c,*t=s;while(c=gc(),c<32);*s++=c;while(c=gc(),c>32)*s++=c;return s-t;}
template <typename T>
in void write(T x,char t)
{
re y=0;if(x<0) y=1,x=-x;while(z[++Z]=x%10+48,x/=10);
if(y) z[++Z]='-';while(sr[++C]=z[Z],--Z);sr[++C]=t;
}
in void write(char *s) {re l=strlen(s);for(re i=0;i<l;i++,*s++)sr[++C]=*s;sr[++C]='\n';}
in void ot() {fwrite(sr,1,C+1,stdout);C=-1;}
};
using namespace fast_io;
const int N=1e5+5;
const ll inf=1e18;
int cnt=1,sum,tot,n,s,t,m,k;
int h[N],l,r,q[N],vis[N],a[N];
ll ans,maxflow,dis[N];
struct did{int u,next,to,f,w;}e[N*21];
in void add(re a,re b,re c,re d)
{
e[++cnt]=(did){a,h[a],b,c,d},h[a]=cnt;
e[++cnt]=(did){b,h[b],a,0,-d},h[b]=cnt;
}
int spfa()
{
memset(vis,0,sizeof(vis));fill(dis+1,dis+sum+1,inf);
dis[s]=0;queue<int>q;q.push(s);vis[s]=1;
while(!q.empty())
{
re i=q.front();vis[i]=0;q.pop();
for(re j=h[i],k;k=e[j].to,j;j=e[j].next)
if(e[j].f&&dis[k]>dis[i]+e[j].w)
{
dis[k]=dis[i]+e[j].w;
if(!vis[k]) q.push(k),vis[k]=1;
}
}
return dis[t]<inf;
}
in int dfs(re u,re f)
{
if(u==t) return f; vis[u]=1;
re res=0;
for(re i=h[u],v;v=e[i].to,i&&res<f;i=e[i].next)
if(e[i].f&&!vis[v]&&dis[v]==dis[u]+e[i].w)
{
re t=dfs(v,min(f-res,e[i].f));
res+=t;ans+=(ll)e[i].w*t;
e[i].f-=t;e[i^1].f+=t;
}
if(!res) dis[u]=inf;
return vis[u]=0,res;
}
in void zkw() {while(spfa()) memset(vis,0,sizeof(vis)),maxflow+=dfs(s,1e9);}
void link(re l,re r)
{
static int t[N];
if(l==r) return; re mid=(l+r)>>1,tot=0;
link(l,mid);link(mid+1,r);
for(re i=l;i<=r;i++) t[++tot]=a[i];
sort(t+1,t+tot+1);tot=unique(t+1,t+tot+1)-t-1;
for(re i=1;i<tot;i++) add(sum+i,sum+i+1,1e9,t[i+1]-t[i]),add(sum+i+1,sum+i,1e9,t[i+1]-t[i]);
for(re i=l;i<=r;i++)
{
re j=lower_bound(t+1,t+tot+1,a[i])-t;
(i<=mid)?add(sum+j,n+i,1,0):add(i,sum+j,1,0);
}
sum+=tot;
}
int main()
{
n=read();m=read();s=0,t=sum=n*2+1;
for(re i=1;i<=n;i++) a[i]=read(),add(s,i,1,0),add(i,t,1,m),add(n+i,t,1,0);
link(1,n);zkw();write(ans,'\n');
return ot(),0;
}
LOJ#3097 [SNOI2019]通信 最小费用最大流+cdq分治/主席树/分块优化建图的更多相关文章
- POJ2135 最小费用最大流模板题
练练最小费用最大流 此外此题也是一经典图论题 题意:找出两条从s到t的不同的路径,距离最短. 要注意:这里是无向边,要变成两条有向边 #include <cstdio> #include ...
- 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时间中选出一个时间进行抢劫,并计划抢 ...
- 【LOJ#3097】[SNOI2019]通信(费用流)
[LOJ#3097][SNOI2019]通信(费用流) 题面 LOJ 题解 暴力就直接连\(O(n^2)\)条边. 然后分治/主席树优化连边就行了. 抄zsy代码,zsy代码是真的短 #include ...
- Libre 6013 「网络流 24 题」负载平衡 (网络流,最小费用最大流)
Libre 6013 「网络流 24 题」负载平衡 (网络流,最小费用最大流) Description G 公司有n 个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等.如何用最少搬运量可以使n ...
- Libre 6011 「网络流 24 题」运输问题 (网络流,最小费用最大流)
Libre 6011 「网络流 24 题」运输问题 (网络流,最小费用最大流) Description W 公司有m个仓库和n个零售商店.第i个仓库有\(a_i\)个单位的货物:第j个零售商店需要\( ...
- LibreOJ #6013. 「网络流 24 题」负载平衡 最小费用最大流 供应平衡问题
#6013. 「网络流 24 题」负载平衡 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 ...
- LIbreOJ #6011. 「网络流 24 题」运输问题 最小费用最大流
#6011. 「网络流 24 题」运输问题 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 ...
- LibreOJ #6008. 「网络流 24 题」餐巾计划 最小费用最大流 建图
#6008. 「网络流 24 题」餐巾计划 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 ...
- Libre 6008 「网络流 24 题」餐巾计划 (网络流,最小费用最大流)
Libre 6008 「网络流 24 题」餐巾计划 (网络流,最小费用最大流) Description 一个餐厅在相继的N天里,第i天需要Ri块餐巾(i=l,2,-,N).餐厅可以从三种途径获得餐巾. ...
随机推荐
- 改变主程序的入口 main
main只是开发工具所规定的一个特殊函数名称而已.它既不是程序的入口,也不是必须要有的函数. 程序的入口点记录在可执行文件中的一个数据,该数据标明程序从哪个位置开始执行,这个数据是连接程序的时候由li ...
- 设计模式(2): 响应store中数据的变化
概述 最近最近做项目的时候总会思考一些大的应用设计模式相关的问题,我把自己的思考记录下来,供以后开发时参考,相信对其他人也有用. store里面响应数据变化 通常情况下,我们会把数据存在store里面 ...
- NW.js
1.package.json属性说明: ——window窗口外观常用属性包括: title : 字符串,设置默认 title width/height : 主窗口的大小 toolbar : bool ...
- es为什么要取消type? 或者为什么一个index下多个type会有问题
同一个index下的不同的type下的相同的filed,在同一个index下其实会被认为是同一个filed. 否则,不同type中的相同字段名称就会在处理中出现冲突的情况,导致Lucene处理效率下降
- python学习中
python中的单引号.双引号.三引号的用法 网上也查找了资料,理解的都有些费劲 就自己验证了一下(主要是目前掌握的python知识,不知道什么时候会同时用到这三种引号) 用python3验证的 单引 ...
- 20191128 Spring Boot官方文档学习(9.11-9.17)
9.11.消息传递 Spring Boot提供了许多包含消息传递的启动器.本部分回答了将消息与Spring Boot一起使用所引起的问题. 9.11.1.禁用事务JMS会话 如果您的JMS代理不支持事 ...
- Vim文本编辑工具
4文本编辑工具Vim Vim是vi的升级版,编辑文本时vi不会显示颜色而vim会显示颜色. 安装vim工具 #yum install –y vim-enhanced Vim有三种模式:一般模式. ...
- 牛客练习赛46 E 华华和奕奕学物理 (树状数组)
https://ac.nowcoder.com/acm/contest/894/E 一开始写了一个简单的模拟 通过率只有5%...... 看题解真的理解了好久!!肥宅大哭orz 题解如下 最后一句:“ ...
- [转帖]Windows下cwRsyncServer双机连续同步部署
Windows下cwRsyncServer双机连续同步部署 https://www.cnblogs.com/nulige/p/7607503.html 找时间做一下测试 应该能更好的实现 自动部署的功 ...
- IDEA 快捷键 (长期更新)
自动清除无效 import 和 清除无效 import ctrl+alt+o