費用流,有點玄妙node
顯然按照最小路徑覆蓋那題的建圖思路,把一個點拆成兩種點,一種是從這個點出去,標成\(x_{i}\),一種是輸入到這個點,使得兩條路徑合成一條(或者是新建一條),標成\(y_i\)c++
源點向每一個\(x_i\)流一條容量爲1,費用爲0的邊優化
而後向每一個\(y_{i}\)流一條容量爲1,費用爲W的邊ui
每一個\(y_i\)向匯點連一條容量爲1,費用爲0的邊spa
這個時候,若是你充滿夢想,你能夠把全部的\(x_{i}\)到\(y_j\)(\(i < j\))連一條\(|a_{i} - a_{j}|\)的邊code
然而你沒有夢想,你以爲彷佛不太優秀get
而後你能夠分治,把每一層的點分紅左右兩部分,而後把左邊點權值離散化後建出一個前綴最大值節點,串成一條鏈,並在對應的位置連上左邊的\(a_{i}\)it
另外一種狀況把右邊的權值離散化(或者按相同的方式給左邊連負數也行),建出前綴最大值節點,串成一條鏈,在對應位置連上右邊的\(a_{i}\)class
這樣邊數就被優化成\(n\log n\)了queue
#include <bits/stdc++.h> #define fi first #define se second #define pii pair<int, int> #define mp make_pair #define pb push_back #define space putchar(' ') #define enter putchar('\n') #define eps 1e-10 #define ba 47 #define MAXN 1005 //#define ivorysi using namespace std; typedef long long int64; typedef unsigned int u32; typedef double db; template <class T> void read(T &res) { res = 0; T f = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); } while (c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); } res *= f; } template <class T> void out(T x) { if (x < 0) { x = -x; putchar('-'); } if (x >= 10) { out(x / 10); } putchar('0' + x % 10); } struct node { int to, next, cap; int64 val; } E[3000005]; int head[2000005], sumE = 1; int x[1005], y[1005], N, a[1005], W, S, T, Ncnt = 0; void add(int u, int v, int c, int64 a) { E[++sumE].to = v; E[sumE].next = head[u]; E[sumE].cap = c; E[sumE].val = a; head[u] = sumE; } void addtwo(int u, int v, int c, int64 a) { add(u, v, c, a); add(v, u, 0, -a); } int val[1005], tot, pos[1005]; void build(int l, int r) { if (l == r) return; if (r - l + 1 == 2) { addtwo(x[l], y[r], 1, abs(a[l] - a[r])); return; } int mid = (l + r) >> 1; build(l, mid); build(mid + 1, r); tot = 0; for (int i = l; i <= mid; ++i) { val[++tot] = a[i]; } sort(val + 1, val + tot + 1); tot = unique(val + 1, val + tot + 1) - val - 1; for (int i = tot; i >= 1; --i) { pos[i] = ++Ncnt; if (i != tot) addtwo(pos[i + 1], pos[i], 1e9, 0); } for (int i = l; i <= mid; ++i) { int t = lower_bound(val + 1, val + tot + 1, a[i]) - val; addtwo(x[i], pos[t], 1, a[i]); } for (int i = mid + 1; i <= r; ++i) { int t = lower_bound(val + 1, val + tot + 1, a[i]) - val; if (t <= tot) addtwo(pos[t], y[i], 1, -a[i]); } tot = 0; for (int i = mid + 1; i <= r; ++i) val[++tot] = a[i]; sort(val + 1, val + tot + 1); tot = unique(val + 1, val + tot + 1) - val - 1; for (int i = 1; i <= tot; ++i) { pos[i] = ++Ncnt; if (i != 1) addtwo(pos[i - 1], pos[i], 1e9, 0); } for (int i = mid + 1; i <= r; ++i) { int t = lower_bound(val + 1, val + tot + 1, a[i]) - val; addtwo(pos[t], y[i], 1, a[i]); } for (int i = l; i <= mid; ++i) { int t = lower_bound(val + 1, val + tot + 1, a[i]) - val; if (t <= tot) addtwo(x[i], pos[t], 1, -a[i]); } } int64 dis[100005]; int preE[100005]; bool inq[100005]; queue<int> Q; bool SPFA() { for (int i = 1; i <= Ncnt; ++i) dis[i] = 1e18; memset(inq, 0, sizeof(inq)); inq[S] = 1; dis[S] = 0; Q.push(S); while (!Q.empty()) { int u = Q.front(); Q.pop(); inq[u] = 0; for (int i = head[u]; i; i = E[i].next) { if (E[i].cap > 0) { int v = E[i].to; if (dis[v] > dis[u] + E[i].val) { dis[v] = dis[u] + E[i].val; preE[v] = i; if (!inq[v]) { inq[v] = 1; Q.push(v); } } } } } return dis[T] != 1e18; } void Init() { read(N); read(W); S = 2 * N + 1, T = 2 * N + 2; for (int i = 1; i <= N; ++i) { read(a[i]); x[i] = ++Ncnt; y[i] = ++Ncnt; addtwo(S, x[i], 1, 0); addtwo(S, y[i], 1, W); addtwo(y[i], T, 1, 0); } Ncnt += 2; build(1, N); } void Solve() { Init(); int64 ans = 0; while (SPFA()) { ans += dis[T]; int p = T; while (p != S) { int t = preE[p]; E[t].cap -= 1; E[t ^ 1].cap += 1; p = E[t ^ 1].to; } } out(ans); enter; } int main() { #ifdef ivorysi freopen("f1.in", "r", stdin); #endif Solve(); }