ACdream 1103 瑤瑤正式成爲CEO (樹鏈剖分+最小費用最大流)

_題目鏈接:
ACdream 1103

題意:中文題面….

題解:
因爲 C  修改操作要在樹上修改邊權,我們用樹鏈剖分去解決就好了。
然後對於 Q  查詢操作,我們可以用最小費用最大流去求最小費用就可以了。

建圖問題:
假設每條邊都跑了 0  的流量,我們先算出跑了 0  的流量的費用sum=c i   ,然後對於一條邊,當跑了小於 a i   的流量的時候,每次增加一點流量,就相當於減小了 c i   的費用,所以可以把一條邊拆成兩條邊,一條是上界爲 a i   ,費用爲 d i c i   的邊,另一條是上界爲無窮,費用爲 b i +d i   的邊。然後跑網絡流就可以了。
跑完最小費用最大流後+sum  就是答案。即代碼中的:sum+G.MCMF(n+1,u). 
加了讀入掛快100ms  左右.

AC代碼:

/*
* this code is made by LzyRapx
* Problem: 1103
* Verdict: Accepted
* Submission Date: 2017-07-11 19:11:24
* Time: 652MS
* Memory: 2504KB
*/
#include<stdio.h>
#include<iostream>
#include<queue>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long ll;
#define lson rt<<1
#define rson rt<<1 | 1
const int INF = 0x3f3f3f3f;
const int maxn = 510;
const int maxm = 4*(1000+2000+12);
int read(){ int v = 0, f = 1;char c =getchar();
while( c < 48 || 57 < c ){if(c=='-') f = -1;c = getchar();}
while(48 <= c && c <= 57) v = v*10+c-48, c = getchar();
return v*f;}
struct MinCostMaxFlow{
    int head[maxn],pnt[maxm],cap[maxm];
    int 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 += 1LL*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);  
        u=read(),v=read(),a=read(),b=read(),c=read(),d=read();
    }
}tree[maxn],edge[maxm];

int idx[maxm],pre[maxm],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 push_down(int rt)
        {
            if(p[rt].add != 0){
                p[lson].add += p[rt].add;
                p[rson].add += p[rt].add;
                p[rt].add = 0;
            }
        }
        void update(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)update(lson,l,r,val);
            if(r>mid)update(rson,l,r,val);
        }
        void push_up(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 ;
            }
            push_down(rt);
            push_up(lson);
            push_up(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++)
        {
            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);
        } 
        G.addedge(n + 1, 1, 0,0);
    }
    ll query(int u,int val)
    {
        ST.push_up(1);
        ll sum = 0;

        for(int i = 1;i < n;i++){

            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); 
    }
    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.update(1,SegId[p],SegId[u],val);
            u = fa[p];
            p = top[u];
        }

        if(u != v)
        {
            if(dep[u] < dep[v]){
                swap(u,v);
            }
            ST.update(1, SegId[v] + 1, SegId[u],val);
        }
    }
    inline void work()
    {
        //scanf("%d%d",&n,&m);
        n=read(),m=read();

        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);

    //  cout<<"finish"<<endl;

        int Q;
    //  scanf("%d",&Q);
        Q=read();
        int a,b,c;
        while(Q--)
        {
            char op[5];
            scanf("%s",op);
            if(op[0]=='Q')
            {
                //scanf("%d%d",&a,&b);
                a=read(),b=read();
            //  cout<<"scanf finish"<<endl;     
                printf("%lld\n",query(a,b));
            }
            else if(op[0]=='C')
            {
                //scanf("%d%d%d",&a,&b,&c);
                a=read(),b=read(),c=read();
                modify(a,b,c);
            }
        }
    }
}gao;

int main()
{
    gao.work();

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