「SNOI2019」通信

#3097. 「SNOI2019」通信

Summarize

题目概括咕咕咕(这个好写!)

Solution

可以参考 「SNOI2017」炸弹 的解法,线段树优化建图。

本题只需扩展一个维度,用类似可持久化线段树的东西优化建图即可。

网络流建模最小权路径覆盖。

代码极端毒瘤且致郁。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#include <bits/stdc++.h>
using namespace std;
#define ri register
#define id(x) (lower_bound(b + 1, b + L + 1, x) - b)
#define rid(x) b[x]
#define lson(x) node[x].l
#define rson(x) node[x].r
#define node_id(x) node[x].node_id
#define sum(x) node[x].sum
typedef long long ll;
typedef pair<int, ll> pii;

const int INF = 0x3f3f3f3f;
const int MAXN = 50005;
const int MAXM = 50005;
int cnt_node = 0;
namespace MCMF {
struct Edge {
int u, v, val, cos, next;
} e[MAXM * 2];
int n, m, t = 1, Head[MAXN], v[MAXN], S, T;
deque<int> q;
ll d[MAXN], Delta;
inline void AddEdge(int x, int y, int v, int c) {
e[++t] = (Edge){ x, y, v, c, Head[x] }, Head[x] = t;
e[++t] = (Edge){ y, x, 0, -c, Head[y] }, Head[y] = t;
}
inline bool Relabel(void) {
memset(d, 0x3f, sizeof d);
memset(v, 0, sizeof v);
d[T] = 0, v[T] = 1, q.push_front(T);
while (!q.empty()) {
int x = q.front();
q.pop_front(), v[x] = 0;
if (q.size() > 1 && d[q.front()] > d[q.back()])
swap(q.front(), q.back());
for (int i = Head[x], y; i; i = e[i].next)
if (e[i ^ 1].val && d[y = e[i].v] > d[x] + e[i ^ 1].cos) {
d[y] = d[x] + e[i ^ 1].cos;
if (v[y])
continue;
v[y] = true, q.push_back(y);
if (q.size() > 1 && d[q.front()] > d[q.back()])
swap(q.front(), q.back());
}
}
return d[S] != d[0];
}
inline int Dinic(int x, int flow) {
if (!flow || x == T)
return flow;
int residue = flow;
v[x] = true;
for (int i = Head[x], y; i; i = e[i].next)
if (e[i].val && !v[y = e[i].v] && !e[i].cos) {
int k = Dinic(y, min(e[i].val, residue));
e[i].val -= k, e[i ^ 1].val += k;
if ((residue -= k) == 0)
break;
}
return flow - residue;
}
inline pii PrimalDual(void) {
int Maxflow = 0;
ll Mincost = 0;
while (Relabel()) {
for (int i = 2; i <= t; i++) e[i].cos += d[e[i].v] - d[e[i].u];
Delta += d[S];
int Flow = 0;
while (memset(v, 0x00, sizeof v), (Flow = Dinic(S, INF)))
Maxflow += Flow, Mincost += 1ll * Flow * Delta;
}
return pii(Maxflow, Mincost);
}
} // namespace MCMF
int n, w;
pair<ll, int> a[MAXN];
ll b[MAXN], c[MAXN];
int L;

int root0[MAXN], root1[MAXN];
int pos0[MAXN], pos1[MAXN];

struct Node {
int l, r, node_id, sum;
} node[MAXN * 22];
int cnt = 0;

void AddEdge(int u, int l, int r, int p, bool t) {
int mid = (l + r) >> 1;
int llen = mid - l + 1, rlen = r - mid;
int lsum = sum(lson(u)), rsum = sum(rson(u));
if (lson(u))
MCMF ::AddEdge(node_id(u), node_id(lson(u)), lsum, llen == 1 ? (t == 0 ? -c[l] : c[l]) : 0);
if (rson(u))
MCMF ::AddEdge(node_id(u), node_id(rson(u)), rsum, rlen == 1 ? (t == 0 ? -c[r] : c[r]) : 0);
}

void insert(int v, int& u, int l, int r, int p, bool t) {
u = ++cnt;
if (l == r) {
sum(u) = 1;
node_id(u) = l;
return;
}
node_id(u) = ++cnt_node;
int mid = (l + r) >> 1;
if (p <= mid)
insert(lson(v), lson(u), l, mid, p, t), rson(u) = rson(v);
else
insert(rson(v), rson(u), mid + 1, r, p, t), lson(u) = lson(v);
sum(u) = sum(lson(u)) + sum(rson(u));
AddEdge(u, l, r, p, t);
}

void query(int u, int l, int r, int ql, int qr, int cur, int num, bool t) {
if (u == 0)
return;
if (ql <= l && r <= qr) {
MCMF ::AddEdge(cur, node_id(u), sum(u), l == r ? abs(c[num] - c[l]) : (t == 0 ? c[num] : -c[num]));
return;
}
int mid = (l + r) >> 1;
if (ql <= mid)
query(lson(u), l, mid, ql, qr, cur, num, t);
if (mid < r)
query(rson(u), mid + 1, r, ql, qr, cur, num, t);
}

int main() {
scanf("%d%d", &n, &w);
for (int i = 1; i <= n; ++i) scanf("%lld", &a[i].first), b[i] = c[i] = a[i].first, a[i].second = i;
sort(b + 1, b + n + 1);
L = unique(b + 1, b + n + 1) - b - 1;
sort(a + 1, a + n + 1);
cnt_node = n;
root0[0] = ++cnt, node_id(root0[0]) = ++cnt_node;
for (int i = 1; i <= n; ++i) {
pos0[id(a[i].first)] = i;
insert(root0[i - 1], root0[i], 1, n, a[i].second, 0);
}
reverse(a + 1, a + n + 1);
root1[0] = ++cnt, node_id(root1[0]) = ++cnt_node;
for (int i = 1; i <= n; ++i) {
pos1[id(a[i].first)] = i;
insert(root1[i - 1], root1[i], 1, n, a[i].second, 1);
}
MCMF ::S = ++cnt_node, MCMF ::T = ++cnt_node;
for (int i = 1; i < n; ++i) {
query(root0[pos0[id(c[i])]], 1, n, i + 1, n, ++cnt_node, i, 0);
query(root1[pos1[id(c[i])]], 1, n, i + 1, n, cnt_node, i, 1);
MCMF ::AddEdge(MCMF ::S, cnt_node, 1, 0);
MCMF ::AddEdge(i, MCMF ::T, 1, 0);
MCMF ::AddEdge(MCMF ::S, i, 1, w);
}
MCMF ::AddEdge(MCMF ::S, ++cnt_node, 1, 0);
MCMF ::AddEdge(n, MCMF ::T, 1, 0);
MCMF ::AddEdge(MCMF ::S, n, 1, w);
pii ans = MCMF ::PrimalDual();
printf("%lld\n", ans.second);
return 0;
}

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×