「SNOI2019」通信 分治优化费用流建图
题意:
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」通信 分治优化费用流建图的更多相关文章
- 「SNOI2019」通信 分治建图
根据题意 每个点可以直接与S,T相连 也可以和前面的哨站相连 暴力建边的话 有n2条边 要用分治优化建边: 类似于归并排序 先对每一层分为左半边与右半边 对每一半都拿出来先排序去重后 直接排成一条链建 ...
- 【LOJ】#3097. 「SNOI2019」通信
LOJ#3097. 「SNOI2019」通信 费用流,有点玄妙 显然按照最小路径覆盖那题的建图思路,把一个点拆成两种点,一种是从这个点出去,标成\(x_{i}\),一种是输入到这个点,使得两条路径合成 ...
- 「SNOI2019」通信
题目 还好我没生在陕西啊 首先发现这个题不能\(dp\),数据范围不大,好像一种网络流的样子啊 哎等等,这样向后面连边不是一个\(DAG\)吗,这不是最小权路径覆盖的板子吗 于是我们套路的拆点,对于一 ...
- Codeforces 362E Petya and Pipes 费用流建图
题意: 给一个网络中某些边增加容量,增加的总和最大为K,使得最大流最大. 费用流:在某条边增加单位流量的费用. 那么就可以2个点之间建2条边,第一条给定边(u,v,x,0)这条边费用为0 同时另一条边 ...
- POJ2516K次费用流建图
Description: N个订单(每个订单订K种商品),M个供应商(每个供应商供应K种商品),K种商品,后N行,表示每一个订单的详细信息,后M行表示每个供应商供应的详细信息,后K 个N * M的矩阵 ...
- HDU 6611 K Subsequence(Dijkstra优化费用流 模板)题解
题意: 有\(n\)个数\(a_1\cdots a_n\),现要你给出\(k\)个不相交的非降子序列,使得和最大. 思路: 费用流建图,每个点拆点,费用为\(-a[i]\),然后和源点连边,和后面非降 ...
- hdu4411 经典费用里建图
题意: 给以一个无向图,0 - n,警察在0,他们有k个警队,要派一些警队去1--n个城市抓小偷, 问所有吧所有小偷全抓到然后在返回0的最小路径和是多少,当地i个城市被攻击的时候他会通知i ...
- 【LOJ】#3098. 「SNOI2019」纸牌
LOJ#3098. 「SNOI2019」纸牌 显然选三个以上的连续牌可以把他们拆分成三个三张相等的 于是可以压\((j,k)\)为有\(j\)个连续两个的,有\(k\)个连续一个的 如果当前有\(i\ ...
- Loj #3096. 「SNOI2019」数论
Loj #3096. 「SNOI2019」数论 题目描述 给出正整数 \(P, Q, T\),大小为 \(n\) 的整数集 \(A\) 和大小为 \(m\) 的整数集 \(B\),请你求出: \[ \ ...
随机推荐
- Struct和Union的sizeof计算
struct 结构体的大小不是简单的成员相加,要考虑存储空间的字节对齐 1.空结构体的大小为1 2.含有static的结构体在计算大小时不算上static变量,因为static存储在全局数据空间,而s ...
- shell编程:向函数中传递参数
cal.sh sh cal.sh 20 + 10 实现这样传参的函数(shell不是一个严谨的编程语言,参数这种是不用定义的,函数中直接引用,shell执行中直接写) #!/bin/bash # ca ...
- MyBatis笔记一:GettingStart
MyBatis笔记一:GettingStart 1.MyBatis优点 我们的工具和各种框架的作用就是为了我们操作数据库简洁,对于一些数据库的工具能帮我们少写一些处理异常等等的代码,但是他们并不是自动 ...
- Oracle备份统计信息
Oracle可以通过DBMS_STATS.GET_TABLE_STATS 收集表的统计信息,一般的收集方法如下: DBMS_STATS.GATHER_TABLE_STATS(OWNNAME => ...
- Gym 102007I 二分 网络流
题意:给你一张图,每个城市有一些人,有不超过10个城市有避难所,避难所有容量上限,问最快多久可以让所有人进入避难所? 思路:二分时间,对于每个时间跑一遍最大流,判断最大流是不是人数即可.我们还需要用二 ...
- Ubuntu更换阿里云数据源
sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak sudo vim /etc/apt/sources.list 将里面的内容全部删除修改成 ...
- Vue 一些零零散散~
1. F5刷新不会触发vue的destroyed事件. 2. computed 的 vuex 数据 ------> beforeCreated: undefined / creat ...
- python_django_上传文件
存储路径: 存储在服务器的项目的static/upfile(你说了算的文件名,但是一般俺们叫这个)文件中 配置: 配置settings.py文件 MDEIA_ROOT = os.path.join(B ...
- fiddler增加ip以及响应时间列
最近打算看一下移动端app的响应等请求,这里打算用fillder来查看appium的模拟出发请求的操作来查看结果, 所以我们需要在左侧的面板增加我们所需要的ip,响应时间等数据以方便我们查看 fidd ...
- Python改变当前工作目录
import os print(os.getcwd()) # 打印当前工作目录 os.chdir('/Users/<username>/Desktop/') # 将当前工作目录改变为`/U ...