这题真让人自闭…我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. JVM性能优化系列-(5) 早期编译优化

    5. 早期编译优化 早起编译优化主要指编译期进行的优化. java的编译期可能指的以下三种: 前端编译器:将.java文件变成.class文件,例如Sun的Javac.Eclipse JDT中的增量式 ...

  2. 自动化测试中,cookie的调用方法。

    以cookie为例 方法一: 将返回的cookie写到setUp()中,每次执行用例之前就会调用一次. 如: class AA(unittest.TestCase): def setUp(self): ...

  3. Vue中的$Bus使用

    Vue中的$Bus使用 将Bus单独抽离成一个文件 Bus.js import Vue from 'vue'; let Bus = new Vue(); export default Bus; 创建两 ...

  4. BOS只读状态修改

    update T_META_OBJECTTYPE set FSUPPLIERNAME ='PAEZ',FPACKAGEID =null

  5. 架构师成长系列 | 从 2019 到 2020,Apache Dubbo 年度回顾与总结

    作者 | 刘军(陆龟)Apache Dubbo PMC 本文整理自架构师成长系列 2 月 18 日直播课程. 关注"阿里巴巴云原生"公众号,回复 "218",即 ...

  6. Vue之计算属性Computed和属性监听Watch,Computed和Watch的区别

    一. 计算属性(computed) 1.计算属性是为了模板中的表达式简洁,易维护,符合用于简单运算的设计初衷. 例如: <div id="app"> {{ myname ...

  7. git rm与git rm --cached的区别

    git rm与git rm --cached的区别 当我们需要删除暂存区或分支上的文件, 同时工作区也不需要这个文件了, 可以使用. git rm file_path git commit -m 'd ...

  8. Vim 全选命令

    ggVG稍微解释一下上面的命令gg 让光标移到首行,在vim才有效,vi中无效V   是进入Visual(可视)模式G  光标移到最后一行选中内容以后就可以其他的操作了,比如:d  删除选中内容y   ...

  9. C语言程序设计(实验一)

    实验项目:1.3.2,1.3.3,1.3.4,2.3.1,2.3.2 姓名:邹琼   实验地点:家 实验时间:2020年2月28日 一.实验目的与要求 1.实验目的 掌握DEVC++的安装方法,并实现 ...

  10. XSY2666

    题意 有\(n\)种颜色的球,第i种有\(a_i\)个.设\(m=\sum a_i\).你要把这\(m\)个小球排成一排.有\(q\)个询问,每次给你一个\(x\),问你有多少种方案使得相邻的小球同色 ...