Acdream1103 瑶瑶正式成为CEO(费用流+树剖)

来源:互联网 发布:hp网络打印机m701 编辑:程序博客网 时间:2024/04/29 20:30

题目链接

中文题意就略去。求1到u的最小费用可以用费用流来做,其他的就直接遍历一遍。那么铁路的a值的更改需要用树剖来维护,
并且每次查询前需要把线断树中的a值更新到tree,再重新构网络流的图跑费用流。先算出流量为0时的费用 sum=ci
然后对于每单位流量,相当于其经过的边要少花c,当流量超过了a时就不能相当于少花了,所以这里需要拆边,分为流量小于等于
a和大于a,费用分别为d - c和d + b。

/*****************************************Author      :Crazy_AC(JamesQi)Time        :2016/08/27File 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 | 1typedef 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;}
0 0
原创粉丝点击