题解 洛谷 P5331 【[SNOI2019]通信】
考虑用费用流解决本题。
每个哨站看作一个点,并将其拆为两个点,建图方式为:
\(S \longrightarrow x_i\) 容量为\(1\),费用为\(0\)
\(x_i \longrightarrow T\) 容量为\(1\),费用为\(w\)
\(x_i \longrightarrow x^\prime_j\ (i>j)\) 容量为\(1\),费用为\(|a_i-a_j|\)
\(x^\prime_i \longrightarrow T\) 容量为\(1\),费用为\(0\)
这样就可以满足题目要求了,跑最小费用最大流即可求解,但发现边数为\(n^2\)级别,所以要考虑优化建图。
一个点在和拆出来的点连边时,只会向下标比其小的点连边,所以可以通过分治来实现优化建图。
对于区间\([l,r]\),分成两个区间\([l,mid]\)和\([mid+1,r]\),每次从右区间向左区间连边。还需考虑费用的绝对值如何处理,可以把这一区间内所有的权值排序去重,然后连成一条链,链上边的费用为相邻两点的权值之差,然后把这条链作为连接右区间和左区间的虚点。
区间内的点向虚点连边时,只需找到其权值所对应到链上的位置,然后向对应位置连边即可,这样就通过累积权值之间的差值实现了费用的绝对值。
\(code:\)
#include<bits/stdc++.h>
#define maxn 800010
#define inf 2000000000
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag)x=-x;
}
int n,w,tot,cnt,s,t;
int p1[maxn],p2[maxn];
ll a[maxn],b[maxn],dis[maxn];
bool vis[maxn];
struct edge
{
int to,nxt,v;
ll c;
}e[maxn];
int head[maxn],edge_cnt=1;
void add(int from,int to,int val,ll cost)
{
e[++edge_cnt]=(edge){to,head[from],val,cost};
head[from]=edge_cnt;
e[++edge_cnt]=(edge){from,head[to],0,-cost};
head[to]=edge_cnt;
}
bool spfa()
{
for(int i=1;i<=tot;++i) vis[i]=0,dis[i]=inf;
queue<int> q;
q.push(s),dis[s]=0,vis[s]=true;
while(!q.empty())
{
int x=q.front();
q.pop(),vis[x]=false;
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to,v=e[i].v;
ll c=e[i].c;
if(v&&dis[y]>dis[x]+c)
{
dis[y]=dis[x]+c;
if(!vis[y]) q.push(y),vis[y]=true;
}
}
}
return dis[t]!=inf;
}
int dfs(int x,int lim)
{
if(x==t) return lim;
vis[x]=true;
int res=lim,flow;
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to,v=e[i].v;
ll c=e[i].c;
if(!v||dis[y]!=dis[x]+c||vis[y]) continue;
if(flow=dfs(y,min(res,v)))
{
res-=flow;
e[i].v-=flow;
e[i^1].v+=flow;
if(!res) break;
}
}
return lim-res;
}
ll dinic()
{
int flow;
ll sum=0;
while(spfa())
while(flow=dfs(s,inf))
sum+=flow*dis[t];
return sum;
}
void solve(int l,int r)
{
if(l==r) return;
int mid=(l+r)>>1;
solve(l,mid),solve(mid+1,r),cnt=0;
for(int i=l;i<=r;++i) b[++cnt]=a[i];
sort(b+1,b+cnt+1),cnt=unique(b+1,b+cnt+1)-b-1;
for(int i=1;i<cnt;++i)
{
add(tot+i,tot+i+1,inf,b[i+1]-b[i]);
add(tot+i+1,tot+i,inf,b[i+1]-b[i]);
}
for(int i=l;i<=r;++i)
{
int pos=lower_bound(b+1,b+cnt+1,a[i])-b;
if(i>mid) add(p1[i],tot+pos,1,0);
else add(tot+pos,p2[i],1,0);
}
tot+=cnt;
}
int main()
{
read(n),read(w),s=++tot,t=++tot;
for(int i=1;i<=n;++i) read(a[i]);
for(int i=1;i<=n;++i)
{
p1[i]=++tot,p2[i]=++tot;
add(s,p1[i],1,0),add(p1[i],t,1,w),add(p2[i],t,1,0);
}
solve(1,n),printf("%lld",dinic());
return 0;
}
题解 洛谷 P5331 【[SNOI2019]通信】的更多相关文章
- 洛谷 P5331 - [SNOI2019]通信(CDQ 分治优化建图+费用流)
题面传送门 首先熟悉网络流的同学应该能一眼看出此题的建模方法: 将每个点拆成两个点 \(in_i,out_i\),连一条 \(S\to in_i\),容量为 \(1\) 费用为 \(0\) 的边 连一 ...
- 【洛谷P5331】 [SNOI2019]通信
洛谷 题意: \(n\)个哨站排成一列,第\(i\)个哨站的频段为\(a_i\). 现在每个哨站可以选择: 直接连接到中心,代价为\(w\): 连接到前面某个哨站\(j(j<i)\),代价为\( ...
- 题解 洛谷P5018【对称二叉树】(noip2018T4)
\(noip2018\) \(T4\)题解 其实呢,我是觉得这题比\(T3\)水到不知道哪里去了 毕竟我比较菜,不大会\(dp\) 好了开始讲正事 这题其实考察的其实就是选手对D(大)F(法)S(师) ...
- 题解 洛谷 P3396 【哈希冲突】(根号分治)
根号分治 前言 本题是一道讲解根号分治思想的论文题(然鹅我并没有找到论文),正 如论文中所说,根号算法--不仅是分块,根号分治利用的思想和分块像 似却又不同,某一篇洛谷日报中说过,分块算法实质上是一种 ...
- 题解-洛谷P5410 【模板】扩展 KMP(Z 函数)
题面 洛谷P5410 [模板]扩展 KMP(Z 函数) 给定两个字符串 \(a,b\),要求出两个数组:\(b\) 的 \(z\) 函数数组 \(z\).\(b\) 与 \(a\) 的每一个后缀的 L ...
- 题解-洛谷P4229 某位歌姬的故事
题面 洛谷P4229 某位歌姬的故事 \(T\) 组测试数据.有 \(n\) 个音节,每个音节 \(h_i\in[1,A]\),还有 \(m\) 个限制 \((l_i,r_i,g_i)\) 表示 \( ...
- 题解-洛谷P4724 【模板】三维凸包
洛谷P4724 [模板]三维凸包 给出空间中 \(n\) 个点 \(p_i\),求凸包表面积. 数据范围:\(1\le n\le 2000\). 这篇题解因为是世界上最逊的人写的,所以也会有求凸包体积 ...
- 题解-洛谷P4859 已经没有什么好害怕的了
洛谷P4859 已经没有什么好害怕的了 给定 \(n\) 和 \(k\),\(n\) 个糖果能量 \(a_i\) 和 \(n\) 个药片能量 \(b_i\),每个 \(a_i\) 和 \(b_i\) ...
- 题解-洛谷P5217 贫穷
洛谷P5217 贫穷 给定长度为 \(n\) 的初始文本 \(s\),有 \(m\) 个如下操作: \(\texttt{I x c}\),在第 \(x\) 个字母后面插入一个 \(c\). \(\te ...
随机推荐
- 必知必会的8个Python列表技巧
原作者:Nik Piepenbreier 翻译&内容补充:费弗里 原文地址:https://towardsdatascience.com/advanced-python-list-techni ...
- 慕课网--mysql开发技巧一 学习笔记
现在存在下面的两张表,表的结构如下所示 师徒四人表结构:id,user_name,over数据:id user_name over1 唐僧 旃檀功德佛2 猪八戒 净坛使者3 孙悟空 斗战胜佛4 沙僧 ...
- 发布Nuget包时遇到都意外
准备好工具和发布教程.(这些网上都有,我就不说了,就说说我遇到都意外.) 在发布包都过程中,我给我都dll命名为Common.不知道是不是这个原因导致的我包发布上去后,程序对其引用时居然没主动引用进程 ...
- bug和测试报告思维导图
Bug定义: 1.不符合需求的 2.程序本身的报错 3.不符合用户使用习惯的 Bug生命周期: 当我们测试人员提交一个bug的时候,自始bug就有它的生命周期,从开始到结束, 把测试的过程和结果写成文 ...
- mysql语句基本练习
select ename,job from emp where job in ('MANAGER','ANALYET','SALESMAN') 1.查询出工作岗位为MANAGER.ANALYST.SA ...
- 入门大数据---Spark_Streaming与流处理
一.流处理 1.1 静态数据处理 在流处理之前,数据通常存储在数据库,文件系统或其他形式的存储系统中.应用程序根据需要查询数据或计算数据.这就是传统的静态数据处理架构.Hadoop 采用 HDFS 进 ...
- 写给程序员的机器学习入门 (七) - 双向递归模型 (BRNN) - 根据上下文补全单词
这一篇将会介绍什么是双向递归模型和如何使用双向递归模型实现根据上下文补全句子中的单词. 双向递归模型 到这里为止我们看到的例子都是按原有顺序把输入传给递归模型的,例如传递第一天股价会返回根据第一天股价 ...
- sql:主键(primary key)和唯一索引(unique index)区别
主键一定是唯一性索引,唯一性索引并不一定就是主键. 所谓主键就是能够唯一标识表中某一行的属性或属性组,一个表只能有一个主键,但可以有多个候选索引. 因为主键可以唯一标识某一行记录,所以可以确保执行数据 ...
- JVM源码分析之深入分析Object类finalize()方法的实现原理
原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 “365篇原创计划”第十篇. 今天呢!灯塔君跟大家讲: 深入分析Object类finalize()方法的实现原理 finalize 如果 ...
- 介绍web开发中实现会话跟踪的常用技术方法
由于http是无状态的协议,这种特性严重阻碍了客户端与服务器进行动态交互,例如购物车程序,客户在购物车中添加了商品,服务器如何知道购物车已有的物品呢?为了支持客户端与服务器之间的交互,为了弥补http ...