[LOJ # 3097. "SNOI2019" communication

LOJ # 3097. "SNOI2019" communication

Cost flow, a bit mysterious

Obviously cover built according to the shortest path problem that FIG idea, a point to point split into two, one is out of this point, marked as \ (X_ {I} \) , one is inputted to this point, so that the two synthesis of a path (or a new one), marked as \ (y_i \)

Source to each \ (x_i \) flow capacity of a 1, 0 edge cost

Then to each \ (y_ {i} \) stream a capacity of 1, W side cost

Each \ (y_i \) to sink even a capacity of 1, the cost for the side 0

This time, if you can dream, you can put all the \ (x_ {i} \) to \ (y_j \) ( \ (i <J \) ) and even a \ (| a_ {i} - a_ {j} | \) side

However, you do not have dreams, you do not seem to feel good

Then you can partition, the point of each layer is divided into left and right parts, the left point and the weight after the construction of a discrete maximum prefix node, strung together a chain, and connected to the left in the position corresponding to \ ( a_ {i} \)

Another case where the discrete weights right (or left connected to the negative line in the same way also), built a maximum prefix node, one strand strung together, connected at a corresponding position on the right side of \ (a_ {i} \)

Thus the number of edges can be optimized \ (n \ log n \) of

#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();
}

Guess you like

Origin www.cnblogs.com/ivorysi/p/11005838.html