Acdream1103 瑤瑤正式成爲CEO(費用流+樹剖)

題目鏈接

中文題意就略去。求1到u的最小費用可以用費用流來做,其他的就直接遍歷一遍。那麼鐵路的a值的更改需要用樹剖來維護,
並且每次查詢前需要把線斷樹中的a值更新到tree,再重新構網絡流的圖跑費用流。先算出流量爲0時的費用 sum=ci
然後對於每單位流量,相當於其經過的邊要少花c,當流量超過了a時就不能相當於少花了,所以這裏需要拆邊,分爲流量小於等於
a和大於a,費用分別爲d - c和d + b。

/*****************************************
Author      :Crazy_AC(JamesQi)
Time        :2016/08/27
File Name   :
*****************************************/
// #pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
using namespace std;
#define lson rt << 1
#define rson rt << 1 | 1
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int maxn = 510;
const int maxm = 4*(1000 + 2000 + 12);
struct MinCostMaxFlow {
    int head[maxn], pnt[maxm], cap[maxm], flow[maxm], nxt[maxm], ecnt;
    LL cost[maxm];
    void init() {
        memset(head, -1, sizeof head), ecnt = 0;
    }
    inline void addedge(int u,int v,int cp, LL co) {
        pnt[ecnt] = v, cap[ecnt] = cp, cost[ecnt] = co, nxt[ecnt] = head[u], head[u] = ecnt++;
        pnt[ecnt] = u, cap[ecnt] = 0, cost[ecnt] = -co, nxt[ecnt] = head[v], head[v] = ecnt++;
    }
    inline void clear() {
        memset(flow, 0, sizeof flow);
    }
    int pre[maxn], dis[maxn];
    bool vis[maxn];
    bool spfa(int s,int t) {
        memset(dis, INF, sizeof dis);
        queue<int> que;
        que.push(s);
        dis[s] = 0;
        while(!que.empty()) {
            int u = que.front();que.pop();vis[u] = false;
            for (int i = head[u];~i;i = nxt[i]) {
                int v = pnt[i];
                if (cap[i] > flow[i] && dis[v] > dis[u] + cost[i]) {
                    dis[v] = dis[u] + cost[i];
                    pre[v] = i;
                    if (!vis[v]) {vis[v] = true;que.push(v);}
                }
            }
        }
        return dis[t] != INF;
    }
    LL MCMF(int s, int t) {
        LL MinCost = 0;
        while(spfa(s, t)) {
            int ang = INF;
            for (int u = t;u != s;u = pnt[pre[u] ^ 1]) 
                ang = min(ang, cap[pre[u]] - flow[pre[u]]);
            for (int u = t;u != s;u = pnt[pre[u] ^ 1]) {
                flow[pre[u]] += ang;
                flow[pre[u] ^ 1] += ang;
            }
            MinCost += (LL)dis[t] * ang;
        }
        return MinCost;
    }
}G;
struct Edge {
    int u, v, a, b, c, d;
    void read() {
        scanf("%d%d%d%d%d%d", &u, &v, &a, &b, &c, &d);
    }
}tree[maxn], edge[maxm];
int idx[maxm], pre[maxm];
int eid[maxm];
struct Solve {
    int n, m;
    int head[maxn], pnt[maxn*2], nxt[maxn*2], ecnt;
    int Hash[maxm];
    int dep[maxn], size[maxn], son[maxn], fa[maxn], top[maxn], SegId[maxn], tot;
    void init() {
        memset(head, -1, sizeof head), ecnt = tot = 0;
    }
    inline void addedge(int u, int v,int i) {
        pnt[ecnt] = v, idx[ecnt] = i, nxt[ecnt] = head[u], head[u] = ecnt++;
        pnt[ecnt] = u, idx[ecnt] = i, nxt[ecnt] = head[v], head[v] = ecnt++;
    }
    struct Segment {
        struct node {
            int l, r, add;
            node() {}
            node(int l, int r, int add) : l(l), r(r), add(add) {}
        }p[maxn<<2];
        void build(int rt,int l, int r) {
            p[rt] = node(l, r, 0);
            if (l == r) return ;
            int mid = (l + r) >> 1;
            build(lson, l, mid);
            build(rson, mid + 1, r);
        }
        void pushdown(int rt) {
            if (p[rt].add != 0) {
                p[lson].add += p[rt].add;
                p[rson].add += p[rt].add;
                p[rt].add = 0;
            }
        }
        void updata(int rt,int l, int r, int val) {
            if (l <= p[rt].l && p[rt].r <= r) {
                p[rt].add += val;
                return ;
            }
            int mid = (p[rt].l + p[rt].r) >> 1;
            if (l <= mid) updata(lson, l, r, val);
            if (r > mid) updata(rson, l, r, val);
        }
        //把線斷樹上的變化值更新到tree上去
        void push(int rt) {
            if (p[rt].l == p[rt].r) {
                if (p[rt].l > 1) tree[eid[p[rt].l]].a += p[rt].add;
                p[rt].add = 0;
                return ;
            }
            pushdown(rt);
            push(lson);
            push(rson);
        }
    }ST;
    void dfs_first(int u,int f,int depth) {
        fa[u] = f, size[u] = 1, son[u] = -1, dep[u] = depth;
        int maxSize = 0;
        for (int i = head[u];~i;i = nxt[i]) {
            int v = pnt[i];
            if (v == f) continue;
            pre[v] = i;
            dfs_first(v, u, depth + 1);
            size[u] += size[v];
            if (size[v] > maxSize) {
                maxSize = size[v], son[u] = v;
            }
        }
    }
    void dfs_second(int u,int header) {
        SegId[u] = ++tot;top[u] = header; eid[tot] = idx[pre[u]];
        if (son[u] == -1) return ;
        if (son[u] != -1) dfs_second(son[u], header);
        for (int i = head[u];~i;i = nxt[i]) {
            if (pnt[i] != fa[u] && pnt[i] != son[u])
                dfs_second(pnt[i], pnt[i]);
        }
    }
    /*初始化流量圖*/
    inline void InitG() {
        G.init();
        for (int i = 1;i < n;++i) {
            /*紀錄每條tree邊添加到流量圖中的正向邊的編號*/
            Hash[i] = G.ecnt;
            Edge& e = tree[i];
            G.addedge(e.u, e.v, max(e.a, 0), e.d - e.c);
            G.addedge(e.u, e.v, INF, e.d + e.b);
        }
        for (int i = 1;i <= m;++i) {
            Edge& e = edge[i];
            G.addedge(e.u, e.v, max(e.a, 0), e.d - e.c);
            G.addedge(e.u, e.v, INF, e.d + e.b);
        }
        /*vs = n + 1*/
        G.addedge(n + 1, 1, 0, 0);
    }
    LL Query(int u, int val) {
        ST.push(1);/*更新tree中的a值*/
        LL sum = 0;
        for (int i = 1;i < n;++i) {
            /*重新更替流量圖中的cap值*/
            G.cap[Hash[i]] = max(0, tree[i].a);
            sum += (LL)max(0, tree[i].a) * (LL)tree[i].c;
        }
        for (int i = 1;i <= m;++i) 
            sum += (LL)max(0, edge[i].a) * (LL)edge[i].c;
        /*匯點出來的流量*/
        G.cap[G.ecnt - 2] = val;
        G.clear();
        return sum + G.MCMF(n + 1, u);
    }
    /*樹剖維護tree中a值的變化值*/
    void modify(int u,int v,int val) {
        int p = top[u], q = top[v];
        while(p != q) {
            if (dep[p] < dep[q]) {
                swap(p, q);
                swap(u, v);
            }
            ST.updata(1, SegId[p], SegId[u], val);
            u = fa[p];
            p = top[u];
        }
        if (u != v) {
            if (dep[u] < dep[v]) swap(u, v);
            ST.updata(1, SegId[v] + 1, SegId[u], val);
        }
    }
    inline void work() {
        scanf("%d%d", &n, &m);
        init();
        /*添加本地tree*/
        for (int i = 1;i < n;++i) {
            tree[i].read();
            addedge(tree[i].u, tree[i].v, i);
        }
        for (int i = 1;i <= m;++i)
            edge[i].read();
        /*初始化流量圖*/
        InitG();
        /*初始化線斷樹*/
        ST.build(1, 1, n);
        dfs_first(1, -1, 0);
        dfs_second(1, 1);

        int Q;cin >> Q;
        while(Q--) {
            char op[5];
            scanf("%s", op);
            if (op[0] == 'Q') {
                int a, b;
                scanf("%d%d", &a, &b);
                printf("%lld\n", Query(a, b));
            }else {
                int a, b, c;
                scanf("%d%d%d", &a, &b, &c);
                modify(a, b, c);
            }
        }
    }
}gao;
int main(int argc, const char * argv[])
{    
    // freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    // ios::sync_with_stdio(false);
    // cout.sync_with_stdio(false);
    // cin.sync_with_stdio(false);

    gao.work();

    // showtime;
    return 0;
}
發佈了304 篇原創文章 · 獲贊 7 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章