Acdream1103 Yaoyao officially became CEO (expense flow + tree cut)

Topic link

The meaning of the Chinese title is omitted. You can use the cost stream to find the minimum cost from 1 to u, and just traverse the others directly. Then the change of the a value of the railway needs to be maintained by the tree section,
and the a value in the line break tree needs to be updated to the tree before each query, and then the graph running cost flow of the network flow is reconstructed. First calculate the cost when the flow is 0 sum=ci , And
then for each unit of flow, it is equivalent to spend less c on the side it passes. When the flow exceeds a, it cannot be equivalent to less spend, so here needs to be split, divided into flow less than or equal to
a and greater than a, the costs are respectively Is d-c and 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;
}

Guess you like

Origin blog.csdn.net/KIJamesQi/article/details/52334658