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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值