P5331 [SNOI2019]通信 [线段树优化建图+最小费用最大流]
这题真让人自闭…我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]通信 [线段树优化建图+最小费用最大流]的更多相关文章
- 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 ...
- BZOJ5017 [SNOI2017]炸弹 - 线段树优化建图+Tarjan
Solution 一个点向一个区间内的所有点连边, 可以用线段树优化建图来优化 : 前置技能传送门 然后就得到一个有向图, 一个联通块内的炸弹可以互相引爆, 所以进行缩点变成$DAG$ 然后拓扑排序. ...
- 【BZOJ3681】Arietta 树链剖分+可持久化线段树优化建图+网络流
[BZOJ3681]Arietta Description Arietta 的命运与她的妹妹不同,在她的妹妹已经走进学院的时候,她仍然留在山村中.但是她从未停止过和恋人 Velding 的书信往来.一 ...
- 【ARC069F】Flags 2-sat+线段树优化建图+二分
Description 数轴上有 n 个旗子,第 ii 个可以插在坐标 xi或者 yi,最大化两两旗子之间的最小距离. Input 第一行一个整数 N. 接下来 N 行每行两个整数 xi, ...
- 【bzoj5017】[Snoi2017]炸弹 线段树优化建图+Tarjan+拓扑排序
题目描述 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆. 现在 ...
- 【bzoj4699】树上的最短路(树剖+线段树优化建图)
题意 给你一棵 $n$ 个点 $n-1$ 条边的树,每条边有一个通过时间.此外有 $m$ 个传送条件 $(x_1,y_1,x_2,y_2,c)$,表示从 $x_1$ 到 $x_2$ 的简单路径上的点可 ...
- 【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 ...
- 【bzoj3073】[Pa2011]Journeys 线段树优化建图+堆优化Dijkstra
题目描述 Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路.N个国家很快建造好了,用1..N编号,但是他发现道路实在太多了,他要一条条建简直是不可能的!于是他以如下方式建造道路:(a, ...
- 【bzoj4383】[POI2015]Pustynia 线段树优化建图+差分约束系统+拓扑排序
题目描述 给定一个长度为n的正整数序列a,每个数都在1到10^9范围内,告诉你其中s个数,并给出m条信息,每条信息包含三个数l,r,k以及接下来k个正整数,表示a[l],a[l+1],...,a[r- ...
随机推荐
- 学习CSS之如何改变CSS伪元素的样式
一.CSS伪元素 CSS 伪元素用于向某些选择器设置特殊效果. 伪元素的用法如下: selector:pseudo-element {property:value;} CSS 类也可以和伪元素搭配使用 ...
- 在windows系统安装nginx
1.下载Nginx,链接:http://nginx.org/en/download.html 2.解压放到自己的磁盘,双击击运行nginx.exe,会有命令框一闪而过,在浏览器上面输入localhos ...
- 用命令提示符运行简单的Java程序报错
首先用记事本写一个最简单的Java代码,我把文件保存在桌面的HelloWorld文件夹中,这里将记事本的名称改为HelloWorld.java public class HelloWorld{ pub ...
- Windows渗透备忘录
Windows渗透备忘录 mimikatz mimikatz.exe ""privilege::debug"" ""sekurlsa::lo ...
- 将jsp页面转化为图片或pdf升级版(一)(qq:1324981084)
java高级架构师全套vip教学视频,需要的加我qq1324981084 前面我利用httputil将jsp转化为html,之后转化为pdf,但我发现这样错误率比较高,且成功后有得图片没有完全形成.所 ...
- leetcode-简单-栈-逆波兰表达式
根据逆波兰表示法,求表达式的值. 有效的运算符包括 +, -, *, / .每个运算对象可以是整数,也可以是另一个逆波兰表达式. 说明: 整数除法只保留整数部分. 给定逆波兰表达式总是有效的.换句话 ...
- mysql随机抽取数据
-- 慢 ; -- 较慢 SELECT * FROM `table` WHERE id >= (SELECT floor( RAND() * ((SELECT MAX(id) FROM `t ...
- Kakfa集群(2.11-0.10.1.0)版本滚动升级方案
Kafka集群版本升级(2.11-0.10.1.0)升级(2.11-0.10.2.2) 官网升级说明: 一.系统环境Zookeeper集群:172.16.2.10172.16.2.11172.16.2 ...
- MySql优化之mycat
1. 解压mycat,不要放在有中文目录的地方 下载地址:http://dl.mycat.io/1.6-RELEASE/2 .修改mycat解压目录下的conf文件夹中server.xml文件,配置 ...
- Nginx 和Apache 中的虚拟主机的概念
在部署环境的时候,有时候会引用到虚拟主机的概念,什么是虚拟主机呢,博主之前一直把虚拟主机的概念没搞清楚,导致在部署的时候,一直动不动就404 ,或者500,或者服务器不通 所以,什么是虚拟主机呢? 虚 ...