这题真让人自闭…我EK费用流已经死了?…

(去掉define int long long就过了)

我建的边害死我的 spfa 还是spfa已经死了?

按费用流的套路来

首先呢 把点 \(i\) 拆成两个点 \(i\) 和 \(i'\)

令 \(i'\) = \(i+n\)

对任意的 \(i\) 点 建 \(s -> i' -> t\) 表示这个连到控制中心…

\(s -> i -> j ->t\) 表示连到某个哨站…流量为\(1\) 费用为 |\(a_i -a_j\)|

其中 \(s -> i'\) 的流量为\(1\) 费用为\(0\) \(i'->t\) 的流量为 \(1\) 费用为\(W\)

如果直接暴力建图 复杂度是 \(O(n^2)\) 的 边数也是 \(n^2\) 的

显然过不去啊…然后可以考虑权值线段树 离散化完的值最多有 \(n\) 种

然后就按照离散值搞个权值线段树优化建边

按顺序加进去 一定能满足\(i<j\)这个要求 所以像主席树一样 一个个加进去就可以了

线段树的具体做法是 对于每个点开两颗线段树(动态开点

\(p\) 向 \(ls_p,rs_p\)建边……(这个大概就是线段树优化建边的trick…

但是要注意 \(ls_p,rs_p\) 非\(0\) 否则会多一堆没啥用的边…

至于 \(p -> ls_p\) 那么流量为\(inf\) 费用为\(0\) 这样就对结果没啥影响了

然后用 \(i -> j(i<j)\)连边… 第一颗线段树为 \(a_i\) 第二颗为 \(-a_i\) 这样就不用管正负性了…

最后跑个\(MCMF\)就可以过了吧应该(EK能过

#include <bits/stdc++.h>
using namespace std ;
using ll = long long ;
#define rep(i , j , k) for(int i = j ; i <= k ; i ++)
void read(int & x) {
char c = x = 0 ; bool f = 1 ;
while(c < '0' || c > '9') { if(c == '-') f = 0 ; c = getchar() ; }
while(c >= '0' && c <= '9') { x = (x << 1) + (x << 3) + (c & 15) ; c = getchar() ; }
x = f ? x : -x ;
}
const int N = 2e3 + 10 , M = 4e5 + 10 ;
int n , W , s , t , a[N] , A[N] , rt[N][2] , id ;
namespace MCMF {
void cmax(int & x , int y) { if(x < y) x = y ; }
void cmin(int & x , int y) { if(x > y) x = y ; }
struct Edge { int v , nxt , f , c ; } e[M << 1] ;
int ecnt = 1 , head[N << 5] , pre[N << 5] , dis[N << 5] , vis[N << 5] ;
void add(int u , int v , int flow , int cost) { e[++ ecnt] = { v , head[u] , flow , cost } ; head[u] = ecnt ; e[++ ecnt] = { u , head[v] , 0 , -cost } ; head[v] = ecnt ; }
bool spfa(int s) {
memset(dis , 0x3f , sizeof(dis)) ; queue < int > q ; dis[s] = 0 ; q.push(s) ;
while(q.size()) {
int u = q.front() ; q.pop() ; vis[u] = 0 ;
for(int i = head[u] ; i ; i = e[i].nxt) {
int v = e[i].v ;
if(dis[v] > dis[u] + e[i].c && e[i].f) { dis[v] = dis[u] + e[i].c ; pre[v] = i ; if(! vis[v]) { vis[v] = 1 ; q.push(v) ; } }
}
}
return (dis[t] != 0x3f3f3f3f) ;
}
ll upd(ll & maxflow) {
int p = 0 , mn = 1e9 , cost = 0 ;
for(int u = t ; u ^ s ; u = e[p ^ 1].v) cmin(mn , e[p = pre[u]].f) ;
for(int u = t ; u ^ s ; u = e[p ^ 1].v) { e[p = pre[u]].f -= mn ; e[p ^ 1].f += mn ; cost += e[p].c * mn ; }
return maxflow += mn , cost ;
}
void EK(ll & maxflow , ll & mincost) { while(spfa(s)) mincost += upd(maxflow) ; }
}
namespace SegMentTree {
int cnt , ls[N << 5] , rs[N << 5] , _id[N << 5] ;
void build(int pos , int l , int r , int pre , int & p , int to) {
ls[p = ++ cnt] = ls[pre] ; rs[cnt] = rs[pre] ; _id[cnt] = ++ id ;
if(l == r) { MCMF :: add(_id[p] , to , 1 , -A[l]) ; return ; }
int mid = l + r >> 1 ;
(pos <= mid) ? build(pos , l , mid , ls[pre] , ls[p] , to) : build(pos , mid + 1 , r , rs[pre] , rs[p] , to) ;
if(ls[p]) MCMF :: add(_id[p] , _id[ls[p]] , 1e9 , 0) ; if(rs[p]) MCMF :: add(_id[p] , _id[rs[p]] , 1e9 , 0) ;
}
void _build(int pos , int l , int r , int pre , int & p , int to) {
ls[p = ++ cnt] = ls[pre] ; rs[cnt] = rs[pre] ; _id[cnt] = ++ id ;
if(l == r) { MCMF :: add(_id[p] , to , 1 , A[l]) ; return ; }
int mid = l + r >> 1 ;
(pos <= mid) ? _build(pos , l , mid , ls[pre] , ls[p] , to) : _build(pos , mid + 1 , r , rs[pre] , rs[p] , to) ;
if(ls[p]) MCMF :: add(_id[p] , _id[ls[p]] , 1e9 , 0) ; if(rs[p]) MCMF :: add(_id[p] , _id[rs[p]] , 1e9 , 0) ;
}
void upd(int a , int b , int l , int r , int p , int from , int cost) {
if(! p) { return ; }
if(a <= l && r <= b) { MCMF :: add(from , _id[p] , 1 , cost) ; return ; }
int mid = l + r >> 1 ;
if(a <= mid) upd(a , b , l , mid , ls[p] , from , cost) ;
if(b > mid) upd(a , b , mid + 1 , r , rs[p] , from , cost) ;
}
void _upd(int a , int b , int l , int r , int p , int from , int cost) {
if(! p) { return ; }
if(a <= l && r <= b) { MCMF :: add(from , _id[p] , 1 , -cost) ; return ; }
int mid = l + r >> 1 ;
if(a <= mid) _upd(a , b , l , mid , ls[p] , from , cost) ;
if(b > mid) _upd(a , b , mid + 1 , r , rs[p] , from , cost) ;
}
}
signed main() {
read(n) ; read(W) ; s = n * 2 + 1 ; t = id = s + 1 ; rep(i , 1 , n) { read(a[i]) ; A[i] = a[i] ; }
sort(A + 1 , A + n + 1) ; int len = unique(A + 1 , A + n + 1) - A - 1 ; rep(i , 1 , n) { a[i] = lower_bound(A + 1 , A + len + 1 , a[i]) - A ; }
rep(i , 1 , n) { MCMF :: add(s , i + n , 1 , 0) ; MCMF :: add(i + n , t , 1 , W) ; MCMF :: add(i , t , 1 , 0) ; }
rep(i , 1 , n) { SegMentTree :: build(a[i] , 1 , len , rt[i - 1][0] , rt[i][0] , i) ; SegMentTree :: _build(a[i] , 1 , len , rt[i - 1][1] , rt[i][1] , i) ; }
rep(i , 2 , n) { SegMentTree :: upd(1 , a[i] , 1 , len , rt[i - 1][0] , i + n , A[a[i]]) ; SegMentTree :: _upd(a[i] + 1 , len , 1 , len , rt[i - 1][1] , i + n , A[a[i]]) ; }
ll maxflow , mincost ; maxflow = mincost = 0 ; MCMF :: EK(maxflow , mincost) ; printf("%lld\n" , mincost) ;
return 0 ;
}

P5331 [SNOI2019]通信 [线段树优化建图+最小费用最大流]的更多相关文章

  1. BZOJ_4276_[ONTAK2015]Bajtman i Okrągły Robin_线段树优化建图+最大费用最大流

    BZOJ_4276_[ONTAK2015]Bajtman i Okrągły Robin_线段树优化建图+最大费用最大流 Description 有n个强盗,其中第i个强盗会在[a[i],a[i]+1 ...

  2. BZOJ5017 [SNOI2017]炸弹 - 线段树优化建图+Tarjan

    Solution 一个点向一个区间内的所有点连边, 可以用线段树优化建图来优化 : 前置技能传送门 然后就得到一个有向图, 一个联通块内的炸弹可以互相引爆, 所以进行缩点变成$DAG$ 然后拓扑排序. ...

  3. 【BZOJ3681】Arietta 树链剖分+可持久化线段树优化建图+网络流

    [BZOJ3681]Arietta Description Arietta 的命运与她的妹妹不同,在她的妹妹已经走进学院的时候,她仍然留在山村中.但是她从未停止过和恋人 Velding 的书信往来.一 ...

  4. 【ARC069F】Flags 2-sat+线段树优化建图+二分

    Description ​ 数轴上有 n 个旗子,第 ii 个可以插在坐标 xi或者 yi,最大化两两旗子之间的最小距离. Input ​ 第一行一个整数 N. ​ 接下来 N 行每行两个整数 xi, ...

  5. 【bzoj5017】[Snoi2017]炸弹 线段树优化建图+Tarjan+拓扑排序

    题目描述 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足:  Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆.  现在 ...

  6. 【bzoj4699】树上的最短路(树剖+线段树优化建图)

    题意 给你一棵 $n$ 个点 $n-1$ 条边的树,每条边有一个通过时间.此外有 $m$ 个传送条件 $(x_1,y_1,x_2,y_2,c)$,表示从 $x_1$ 到 $x_2$ 的简单路径上的点可 ...

  7. 【BZOJ4276】[ONTAK2015]Bajtman i Okrągły Robin 线段树优化建图+费用流

    [BZOJ4276][ONTAK2015]Bajtman i Okrągły Robin Description 有n个强盗,其中第i个强盗会在[a[i],a[i]+1],[a[i]+1,a[i]+2 ...

  8. 【bzoj3073】[Pa2011]Journeys 线段树优化建图+堆优化Dijkstra

    题目描述 Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路.N个国家很快建造好了,用1..N编号,但是他发现道路实在太多了,他要一条条建简直是不可能的!于是他以如下方式建造道路:(a, ...

  9. 【bzoj4383】[POI2015]Pustynia 线段树优化建图+差分约束系统+拓扑排序

    题目描述 给定一个长度为n的正整数序列a,每个数都在1到10^9范围内,告诉你其中s个数,并给出m条信息,每条信息包含三个数l,r,k以及接下来k个正整数,表示a[l],a[l+1],...,a[r- ...

随机推荐

  1. mysql必知必会-创建高级联结

    使用表别名 使用别名引用被检索的表列 别名除了用于列名和计算字段外,SQL还允许给表名起别名.这样做 有两个主要理由: 缩短SQL语句: 允许在单条 SELECT 语句中多次使用相同的表. 可以看到, ...

  2. 推荐一款疫情期间适合在家办公的远程工具,仅需IP和密码轻松实现远程管理

    这段时间,受疫情影响,很多企业都开启了居家办公模式.但疫情突发,大多数人的办公资料没有拷贝打包,对于居家办公的人,尤其是运维人员来说,很难完成顺利完成工作. 像向日葵.teamviewer之类的远程软 ...

  3. 如何阻止a标签跳转

    <a href="www.baidu.com">百度</a> 上面为我们的a标签,要想阻止它进行跳转我们该怎么办呢? 当然我们有以下的几种办法_______ ...

  4. Luarocks 安装艰难过程

    https://www.cnblogs.com/fanxiaojuan/p/11551268.html

  5. centos yum 安装jdk1.7

    安装: yum -y install java-1.7.0-openjdk-devel.x86_64 环境变量: vi /etc/profile export JAVA_HOME=/usr/lib/j ...

  6. Notability

    Notability 上课记笔记.听网课→Notability 有录音功能, 在原来笔记中新添加空白行(选中之后下移) Notability常用的功能总结 1.纸张有颜色2.荧光笔会盖住文字3.套索工 ...

  7. 页面上icon较多,又不想使用臃肿的结构怎么办?

    [先看效果图] 例如这种排版,常规有两种情况 1.把[“ & ”]+ 白色背景切一起 2.写结构的时候复杂,例如:div>img*2 +文字标签 读到这里,可能有人说,第一种情况为什么两 ...

  8. NAS之NFS/CIFS

    NAS之NFS 为集群中的 Web Server 配置后端存储 NFS:Network File System 网络文件系统,Unix系统之间共享文件的一种协议NFS 的客户端主要为Linux支持多节 ...

  9. P1553 数字反转(升级版)(copy(),reverse(),find(),substr(),erase())

    题目描述 给定一个数,请将该数各个位上数字反转得到一个新数. 这次与 NOIp2011 普及组第一题不同的是:这个数可以是小数,分数,百分数,整数.整数反转是将所有数位对调:小数反转是把整数部分的数反 ...

  10. 【新人赛】阿里云恶意程序检测 -- 实践记录11.3 - n-gram模型调参

    主要工作 本周主要是跑了下n-gram模型,并调了下参数.大概看了几篇论文,有几个处理方法不错,准备下周代码实现一下. xgboost参数设置为: param = {'max_depth': 6, ' ...