[BZOJ3218]A+B problem

題目鏈接BZOJ3218

題目大意
這道題的題面和題目沒有任何關係。以及,題目大意略。

分析
1. 顯然這道題是一個最大流最小割模型。
2. 設S割的點爲黑格,T割的點爲白格;對於每個點i ,由S向i 點連邊,容量爲bi ;由i 向T連邊,容量爲wi ;表示使i 屬於S割會損失i 作爲白格子的優美度;使i 屬於T割會損失i 作爲黑格子的優美度;
3. 由ii 連邊,容量爲pi ;由可以使i 變得奇♂怪的ji 連邊,容量爲INF ;表示若i 屬於S割且j 屬於T割,那麼就會損失pi 的優美度。
4. 然後最大流最小割跑一遍,用(bi+wi)maxflow 即爲答案;但是邊太多(N2) ,會超時
5. 對於每個點,將它以ai 爲權值,對應到權值線段樹上;那麼對於i ,只需要對由[1..i1] 的點集構成的權值線段樹中的區間[li...ri] 連邊就好了,而線段樹上的點之間相互連邊,葉子節點向其對應的點連邊,容量均INF ,但是這樣有N 棵線段樹,邊的數量還是N2
6. 這樣的話,可以用主席樹來減少線段樹的點的數量,邊的數量就變成NlogN 了。

上代碼

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 5e3 + 10;
const int M = 4e5 + 10;
const int INF = 0x3f3f3f3f;

int n;
inline int read() {
    char ch;
    int ans = 0, neg = 1;
    while (!isdigit(ch = getchar()))
        if (ch == '-') neg = -1;
    while (isdigit(ch))
        ans = ans * 10 + ch - '0', ch = getchar();
    return ans * neg;
}

int SS, TT, cnt;
int head[M], len;
#define id(a) ((a) + 2)
struct Lib {
    int st, to, nxt, flow;
    inline void add(int a, int b, int c) {
        st = a, to = b, flow = c;
        nxt = head[a], head[a] = len++;
    }
} lib[M << 1];
inline void makePath(int a, int b, int c) {
    lib[len].add(a, b, c), lib[len].add(b, a, 0);
}

queue <int> Q;
int dep[M], num[M], pre[M], curHead[M];
void bfs() {
    memset(dep, 0x3f, sizeof(dep));
    dep[TT] = 0, Q.push(TT);
    while (!Q.empty()) {
        int tmp = Q.front(); Q.pop();
        for (int p = head[tmp]; p; p = lib[p].nxt) {
            int now = lib[p].to;
            if (!lib[p ^ 1].flow || dep[now] != INF) continue;
            dep[now] = dep[tmp] + 1, Q.push(now);
        }
    }
}
int augment() {
    int tmp = TT, minn = INF;
    while (tmp != SS) {
        minn = min(minn, lib[pre[tmp]].flow);
        tmp = lib[pre[tmp]].st;
    } tmp = TT;
    while (tmp != SS) {
        lib[pre[tmp]].flow -= minn, lib[pre[tmp] ^ 1].flow += minn;
        tmp = lib[pre[tmp]].st;
    }
    return minn;
}
int ISAP() {
    bfs();
    for (int i = 1; i <= cnt; i++) {
        curHead[i] = head[i];
        if (dep[i] != INF) num[dep[i]]++;
    }
    int ans = 0, tmp = SS;
    while (dep[SS] < INF) {
        if (tmp == TT) ans += augment(), tmp = SS;
        bool flag = false;
        for (int &p = curHead[tmp]; p; p = lib[p].nxt) {
            int now = lib[p].to;
            if (lib[p].flow && dep[now] == dep[tmp] - 1) {
                pre[now] = p, tmp = now, flag = true; break;
            }
        }
        if (!flag) {
            int minn = INF;
            if (!--num[dep[tmp]]) break;
            for (int p = head[tmp]; p; p = lib[p].nxt)
                if (lib[p].flow) minn = min(minn, dep[lib[p].to]);
            if (minn < INF) num[dep[tmp] = minn + 1]++;
            curHead[tmp] = head[tmp];
            if (tmp != SS) tmp = lib[pre[tmp]].st;
        }
    }
    return ans;
}

int T[N], lc[M], rc[M];
inline int modify(int a, int p, int poi) {
    int now = ++cnt, tmp = now;
    int l = 1, r = n, mid;
    while (l < r) {
        mid = (l + r) >> 1;
        if (p <= mid) {
            makePath(now, rc[now] = rc[a], INF);
            makePath(now, lc[now] = ++cnt, INF);
            now = lc[now], a = lc[a], r = mid;
        } else {
            makePath(now, lc[now] = lc[a], INF);
            makePath(now, rc[now] = ++cnt, INF);
            now = rc[now], a = rc[a], l = mid + 1;
        }
    }
    makePath(now, id(poi), INF), makePath(now, a, INF);
    return tmp;
}
void calcPath(int a, int l, int r, int ll, int rr) {
    if (!a || ll > rr) return;
    if (l == ll && r == rr) return makePath(cnt, a, INF);
    int mid = (l + r) >> 1;
    if (rr <= mid) return calcPath(lc[a], l, mid, ll, rr);
    else if (ll > mid) return calcPath(rc[a], mid + 1, r, ll, rr);
    calcPath(lc[a], l, mid, ll, mid), calcPath(rc[a], mid + 1, r, mid + 1, rr);
}

int dsc[N];
struct Blc {
    int a, l, r, b, w, p;
    inline void input() {
        a = read(), b = read(), w = read();
        l = read(), r = read(), p = read();
    }
} blc[N];
void calcDsc() {
    for (int i = 1; i <= n; i++)
        blc[i].input(), dsc[i] = blc[i].a;
    sort(dsc + 1, dsc + n + 1);
    for (int i = 1; i <= n; i++) {
        blc[i].a = lower_bound(dsc + 1, dsc + n + 1, blc[i].a) - dsc;
        blc[i].l = lower_bound(dsc + 1, dsc + n + 1, blc[i].l) - dsc;
        blc[i].r = upper_bound(dsc + 1, dsc + n + 1, blc[i].r) - dsc - 1;
    }
}
void init() {
    n = read(), calcDsc();
    SS = 1, TT = 2, len = 2, cnt = id(n);
    for (int i = 1; i <= n; i++)
        makePath(SS, id(i), blc[i].b), makePath(id(i), TT, blc[i].w);
    for (int i = 1; i <= n; i++) {
        makePath(id(i), ++cnt, blc[i].p);
        calcPath(T[i - 1], 1, n, blc[i].l, blc[i].r);
        T[i] = modify(T[i - 1], blc[i].a, i);
    }
}
int figure() {
    int ans = 0;
    for (int i = 1; i <= n; i++)
        ans += blc[i].b + blc[i].w;
    return ans -= ISAP(), ans;
}
int main() {
    init();
    printf("%d\n", figure());
    return 0;
}

以上

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章