题意:

n 个排成一列的哨站要进行通信。第 i 个哨站的频段为 ai。

每个哨站 ii 需要选择以下二者之一:

1.直接连接到控制中心,代价为 W;
2.连接到前面的某个哨站 j(j<i),代价为 |ai−aj|。 每个哨站只能被后面的至多一个哨站连接。

请你求出最小可能的代价和。

题解:

显然的费用流

然后我耿直的n^2建边,觉得我的费用流很快,应该可以过

然后返回了TLE

然后google了一下题解:发现这题卡了n^2建图,需要优化建边

我这里是通过分治优化的

就是类似与建立一个虚点

一个x要向y的一个前缀建图,所以就可以类似前缀和优化建图那样,

按权值排序然后建出一条链,链上两个点之间的流量为INF,费用为权值之差,然后每个点向对应的点连边
但这样建图是错误的,原因在于我们把点排了序,改变了编号顺序,

所以一个点能到达的点不一定是它可以到达的
所以我们要固定在固定编号顺序的情况下这样连边,也就是说x的一个区间和y的一个区间之间这样连边,

要求两个区间不重合,且x的区间比y的区间小
那么很容易想到分治建图,每次让[l,mid]向[mid+1,r]连边,剩下的递归下去就行了

 #include <set>
#include <map>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map> #define pi acos(-1.0)
#define eps 1e-9
#define fi first
#define se second
#define rtl rt << 1
#define rtr rt << 1 | 1
#define bug printf("******\n")
#define mem(a, b) memset(a, b, sizeof(a))
#define name2str(x) #x
#define fuck(x) cout << #x " = " << x << endl
#define sfi(a) scanf("%d", &a)
#define sffi(a, b) scanf("%d %d", &a, &b)
#define sfffi(a, b, c) scanf("%d %d %d", &a, &b, &c)
#define sffffi(a, b, c, d) scanf("%d %d %d %d", &a, &b, &c, &d)
#define sfL(a) scanf("%lld", &a)
#define sffL(a, b) scanf("%lld %lld", &a, &b)
#define sfffL(a, b, c) scanf("%lld %lld %lld", &a, &b, &c)
#define sffffL(a, b, c, d) scanf("%lld %lld %lld %lld", &a, &b, &c, &d)
#define sfs(a) scanf("%s", a)
#define sffs(a, b) scanf("%s %s", a, b)
#define sfffs(a, b, c) scanf("%s %s %s", a, b, c)
#define sffffs(a, b, c, d) scanf("%s %s %s %s", a, b, c, d)
#define FIN freopen("../in.txt", "r", stdin)
#define gcd(a, b) __gcd(a, b)
#define lowbit(x) x & -x
#define IO iOS::sync_with_stdio(false) using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const ULL seed = ;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const int maxn = 1e6 + ;
const int maxm = 8e6 + ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ; struct Cost_MaxFlow {
int s, t, tot, maxflow, head[maxn], vis[maxn], pre[maxn], last[maxn];
LL mincost, maxcost, dis[maxn], disf[maxn];
struct Edge {
int v, w, nxt;
int cost;
} edge[maxm];
queue<int> q; void init() {
tot = ;
mincost = maxcost = ;
memset(head, -, sizeof(head));
} void add(int u, int v, int f, int e) {
edge[++tot].v = v, edge[tot].nxt = head[u], head[u] = tot, edge[tot].w = f, edge[tot].cost = e;
edge[++tot].v = u, edge[tot].nxt = head[v], head[v] = tot, edge[tot].w = , edge[tot].cost = -e;
} bool spfa_max() {
memset(dis, 0xef, sizeof(dis));
q.push(s), dis[s] = , disf[s] = INFLL, pre[t] = -;
while (!q.empty()) {
int u = q.front();
q.pop();
vis[u] = ;
for (int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].v;
if (edge[i].w && dis[v] < dis[u] + edge[i].cost) {
dis[v] = dis[u] + edge[i].cost, last[v] = i, pre[v] = u;
disf[v] = min(disf[u], 1LL * edge[i].w);
if (!vis[v])
vis[v] = , q.push(v);
}
}
}
return ~pre[t];
} void dinic_max() {
while (spfa_max()) {
int u = t;
maxflow += disf[t];
maxcost += disf[t] * dis[t];
while (u != s) {
edge[last[u]].w -= disf[t];
edge[last[u] ^ ].w += disf[t];
u = pre[u];
}
}
} bool spfa_min() {
memset(dis, 0x3f, sizeof(dis));
memset(vis, , sizeof(vis));
memset(disf, 0x3f, sizeof(disf));
q.push(s), dis[s] = , vis[s] = , pre[t] = -;
while (!q.empty()) {
int u = q.front();
q.pop();
vis[u] = ;
for (int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].v;
if (edge[i].w > && dis[v] > dis[u] + edge[i].cost) {
dis[v] = dis[u] + edge[i].cost, pre[v] = u;
last[v] = i, disf[v] = min(disf[u], 1LL * edge[i].w);
if (!vis[v])
vis[v] = , q.push(v);
}
}
}
return pre[t] != -;
} void dinic_min() {
while (spfa_min()) {
int u = t;
maxflow += disf[t];
mincost += disf[t] * dis[t];
while (u != s) {
edge[last[u]].w -= disf[t];
edge[last[u] ^ ].w += disf[t];
u = pre[u];
}
}
}
} F; int n, W, a[maxn], cnt[maxn], sum; void link(int L, int R) {
if (L == R) return;
int num = , mid = (L + R) / ;
for (int i = L; i <= R; i++) cnt[++num] = a[i];
sort(cnt + , cnt + + num);
num = unique(cnt + , cnt + + num) - cnt - ;
for (int i = ; i < num; i++) {
F.add(sum + i, sum + i + , INF, cnt[i + ] - cnt[i]);
F.add(sum + i + , sum + i, INF, cnt[i + ] - cnt[i]);
}
for (int i = L; i <= R; i++) {
if (i <= mid) {
int pos = lower_bound(cnt + , cnt + + num, a[i]) - cnt;
F.add(sum + pos, i + n, , );
} else {
int pos = lower_bound(cnt + , cnt + + num, a[i]) - cnt;
F.add(i, sum + pos, , );
}
}
sum += num;
link(L, mid), link(mid + , R);
} int main() {
#ifndef ONLINE_JUDGE
FIN;
#endif
while (~sffi(n, W)) {
for (int i = ; i <= n; i++) sfi(a[i]);
F.init();
F.s = , F.t = * n + ;
sum = * n + ;
for (int i = ; i <= n; i++) {
F.add(F.s, i, , );
F.add(i + n, F.t, , );
F.add(i, F.t, , W);
}
link(, n);
F.dinic_min();
printf("%lld\n", F.mincost);
}
#ifndef ONLINE_JUDGE
cout << "Totle Time : " << (double) clock() / CLOCKS_PER_SEC << "s" << endl;
#endif
return ;
}

「SNOI2019」通信 分治优化费用流建图的更多相关文章

  1. 「SNOI2019」通信 分治建图

    根据题意 每个点可以直接与S,T相连 也可以和前面的哨站相连 暴力建边的话 有n2条边 要用分治优化建边: 类似于归并排序 先对每一层分为左半边与右半边 对每一半都拿出来先排序去重后 直接排成一条链建 ...

  2. 【LOJ】#3097. 「SNOI2019」通信

    LOJ#3097. 「SNOI2019」通信 费用流,有点玄妙 显然按照最小路径覆盖那题的建图思路,把一个点拆成两种点,一种是从这个点出去,标成\(x_{i}\),一种是输入到这个点,使得两条路径合成 ...

  3. 「SNOI2019」通信

    题目 还好我没生在陕西啊 首先发现这个题不能\(dp\),数据范围不大,好像一种网络流的样子啊 哎等等,这样向后面连边不是一个\(DAG\)吗,这不是最小权路径覆盖的板子吗 于是我们套路的拆点,对于一 ...

  4. Codeforces 362E Petya and Pipes 费用流建图

    题意: 给一个网络中某些边增加容量,增加的总和最大为K,使得最大流最大. 费用流:在某条边增加单位流量的费用. 那么就可以2个点之间建2条边,第一条给定边(u,v,x,0)这条边费用为0 同时另一条边 ...

  5. POJ2516K次费用流建图

    Description: N个订单(每个订单订K种商品),M个供应商(每个供应商供应K种商品),K种商品,后N行,表示每一个订单的详细信息,后M行表示每个供应商供应的详细信息,后K 个N * M的矩阵 ...

  6. HDU 6611 K Subsequence(Dijkstra优化费用流 模板)题解

    题意: 有\(n\)个数\(a_1\cdots a_n\),现要你给出\(k\)个不相交的非降子序列,使得和最大. 思路: 费用流建图,每个点拆点,费用为\(-a[i]\),然后和源点连边,和后面非降 ...

  7. hdu4411 经典费用里建图

    题意:       给以一个无向图,0 - n,警察在0,他们有k个警队,要派一些警队去1--n个城市抓小偷, 问所有吧所有小偷全抓到然后在返回0的最小路径和是多少,当地i个城市被攻击的时候他会通知i ...

  8. 【LOJ】#3098. 「SNOI2019」纸牌

    LOJ#3098. 「SNOI2019」纸牌 显然选三个以上的连续牌可以把他们拆分成三个三张相等的 于是可以压\((j,k)\)为有\(j\)个连续两个的,有\(k\)个连续一个的 如果当前有\(i\ ...

  9. Loj #3096. 「SNOI2019」数论

    Loj #3096. 「SNOI2019」数论 题目描述 给出正整数 \(P, Q, T\),大小为 \(n\) 的整数集 \(A\) 和大小为 \(m\) 的整数集 \(B\),请你求出: \[ \ ...

随机推荐

  1. 把数字翻译成字符串 --剑指offer 46题

    # 给一个字符串,按如下规则把它翻译成字符串:1翻译成a,2翻译成b,...25翻译成z:一个数可以有多种翻译方式,比如122可以翻译成abb和kb还可以翻译成aw即3种翻译方式.计算一个数字有几种翻 ...

  2. 排序(分组后排序&整排)

    一.整排 要求:根据score进行排名,分数相同,名次相同,且连续 表如下图: sql语句: 方法一:select a.score, (select count(distinct b.score) f ...

  3. iView的表单table

    // html<div class="exam-list"> <Table :columns="columns7" :data="d ...

  4. go之linux安装

    下载地址:https://golang.org/dl/ ubuntu16.04安装过程 官方安装文档:https://golang.org/doc/install?download=go1.11.4. ...

  5. linux文本处理工具篇

    一.常用简单工具 cat [OPTION]... [FILE]...  -E:显示行的结束符$ -n:对显示出的每一行进行编号. -A:显示所有控制符 -s:压缩连续空行为一行 more:分页查看文件 ...

  6. PHP操作XML方法之 XML Expat Parser

    XML Expat Parser 简介 此PHP扩展实现了使用PHP支持JamesClark编写的expat.此工具包可解析(但不能验证)XML文档.它支持PHP所提供的3种字符编码:US-ASCII ...

  7. ES5新增方法(数组,字符串,对象)

    一.数组方法 迭代(遍历)方法:forEach().map().filter().some().every(): 1. array. forEach(function(value,index,arr) ...

  8. Shell内置命令 eval

  9. 如何通过cmd命令远程重启或远程关闭Windows服务器

    一.想要远程控制服务器,前提条件是远程服务器需要开启IPC$ ,且本地能访问远程服务器445端口 1.开启ipc$ net share IPC$ 2.如果只指定管理员才有执行ipc$的权限 net s ...

  10. shell 编程四剑客简介 find sed grep awk(微信公众号摘抄)

    一,Shell编程四剑客之Find 通过如上基础语法的学习,读者对Shell编程有了更近一步的理解,Shell编程不再是简单命令的堆积,而是演变成了各种特殊的语句.各种语法.编程工具.各种命令的集合. ...