「SNOI2019」通信 分治建图

 根据题意 每个点可以直接与S,T相连 也可以和前面的哨站相连 暴力建边的话 有n2条边

要用分治优化建边:

类似于归并排序 先对每一层分为左半边与右半边 对每一半都拿出来先排序去重后 直接排成一条链建边

if (l == r) {
                return ;
        }
        int mid = (l + r) >> 1;
        solve(l, mid), solve(mid + 1, r);
        int cnt = 0;
        for (int i = l; i <= r; i++) {
                aa[++cnt] = a[i];
        }
        sort(aa + 1, aa + 1 + cnt);
        cnt = unique(aa + 1, aa + cnt + 1) - aa - 1;
        int now = MCMF::MAXP;
        for (int i = 1; i < cnt; i++) {
                MCMF::addedge(now + i, now + i + 1, inf, aa[i + 1] - aa[i]);
                MCMF::addedge(now + i + 1, now + i, inf, aa[i + 1] - aa[i]);
        }

然后对于区间内的每个数 前半边的出后半边的入

        for (int i = l; i <= r; i++) {
                int aim = lower_bound(aa + 1, aa + cnt + 1, a[i]) - aa;
                if (i <= mid) {
                        MCMF::addedge(now + aim, i + n, 1, 0);
                } else {
                        MCMF::addedge(i, now + aim, 1, 0);
                }
        }
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long long JQK;
const int inf = INT_MAX / 2;
namespace MCMF {
        const JQK INF = LLONG_MAX / 2;
        const int MAXN = 50500, MAXM = 130000;
        int Head[MAXN], cur[MAXN], to[MAXM << 1], nxt[MAXM << 1], f[MAXM << 1], ed = 1;
        int S, T, MAXP, MAXF, pre[MAXN];
        JQK lev[MAXN], cost[MAXM << 1];
        bool exist[MAXN];
        void addedge(int u, int v, int cap, JQK val) {
                //cout << u << " " << v << " " << cap << " " << val << endl;
                to[++ed] = v;
                nxt[ed] = Head[u];
                Head[u] = ed;
                f[ed] = cap;
                cost[ed] = val;
                to[++ed] = u;
                nxt[ed] = Head[v];
                Head[v] = ed;
                f[ed] = 0;
                cost[ed] = -1 * val;
                return;
        }
        bool spfa() {
                int u;
                queue<int>q;
                for (int i = 0; i <= MAXP + 1; i++) {
                        exist[i] = 0;
                        lev[i] = INF;
                }
                //memset(exist, false, sizeof(exist));
                //memset(lev, 127, sizeof(lev));
                lev[S] = pre[S] = 0;
                q.push(S);
                while (q.size()) {
                        u = q.front();
                        q.pop();
                        exist[u] = false;
                        for (int i = Head[u]; i; i = nxt[i])
                                if (f[i] && lev[u] + cost[i] < lev[to[i]]) {
                                        lev[to[i]] = lev[u] + cost[i];
                                        pre[to[i]] = i;
                                        if (!exist[to[i]]) {
                                                exist[to[i]] = true;
                                                q.push(to[i]);
                                        }
                                }
                }
                for (int i = 0; i <= MAXP + 1; i++) {
                        cur[i] = Head[i];
                }
                //memcpy(cur, Head, sizeof(Head));
                return lev[T] != INF;
        }
        JQK Augment() {
                JQK delta = 0x7f7f7f7f;
                for (int i = pre[T]; i; i = pre[to[i ^ 1]])
                        if (f[i] < delta) {
                                delta = f[i];
                        }
                for (int i = pre[T]; i; i = pre[to[i ^ 1]]) {
                        f[i] -= delta;
                        f[i ^ 1] += delta;
                }
                MAXF += delta;
                return delta * lev[T];
        }
        void init(int S1, int T1) {
                MAXF = 0;
                S = S1;
                T = T1;
                return;
        }
        JQK MCMF() {
                JQK ans = 0;
                memset(exist, false, sizeof(exist));
                while (spfa())
                        //ans+=DFS(S,INF)*lev[T];
                {
                        ans += Augment();
                }
                return ans;
        }
}
inline void RR(int &x) {
        char c;
        bool sign = false;
        for (c = getchar(); c < '0' || c > '9'; c = getchar())
                if (c == '-') {
                        sign = true;
                }
        for (x = 0; c >= '0' && c <= '9'; c = getchar()) {
                x = x * 10 + c - '0';
        }
        sign && (x = -x);
}
int n, a[1005], aa[1005];
void solve(int l, int r) {
        if (l == r) {
                return ;
        }
        int mid = (l + r) >> 1;
        solve(l, mid), solve(mid + 1, r);
        int cnt = 0;
        for (int i = l; i <= r; i++) {
                aa[++cnt] = a[i];
        }
        sort(aa + 1, aa + 1 + cnt);
        cnt = unique(aa + 1, aa + cnt + 1) - aa - 1;
        int now = MCMF::MAXP;
        for (int i = 1; i < cnt; i++) {
                MCMF::addedge(now + i, now + i + 1, inf, aa[i + 1] - aa[i]);
                MCMF::addedge(now + i + 1, now + i, inf, aa[i + 1] - aa[i]);
        }
        for (int i = l; i <= r; i++) {
                int aim = lower_bound(aa + 1, aa + cnt + 1, a[i]) - aa;
                if (i <= mid) {
                        MCMF::addedge(now + aim, i + n, 1, 0);
                } else {
                        MCMF::addedge(i, now + aim, 1, 0);
                }
        }
        MCMF::MAXP += cnt;
}
int main() {
        int x;
        int s, t;
        ll W;
        RR(n), RR(x);
        W = x;
        MCMF::MAXP = 2 * n + 3, s = 2 * n + 1, t = 2 * n + 2;
        for (int i = 1; i <= n; i++) {
                RR(a[i]);
                MCMF::addedge(s, i, 1, 0), MCMF::addedge(i, t, 1, W), MCMF::addedge(i + n, t, 1, 0);
        }
        solve(1, n);
        MCMF::init(s, t);
        cout << MCMF::MCMF() << "\n";
        return 0;
}

猜你喜欢

转载自www.cnblogs.com/Aragaki/p/11618485.html