zoukankan      html  css  js  c++  java
  • codeforces CF903G Yet Another Maxflow Problem 线段树

    $ Rightarrow $ 戳我进CF原题

    G. Yet Another Maxflow Problem


    time limit per test: 4 seconds
    memory limit per test: 256 megabytes
    input: standard input
    output: standard output

     

    In this problem you will have to deal with a very special network.
     
    The network consists of two parts: part $ A $ and part $ B $ .
    Each part consists of n vertices; $ i $ -th vertex of part $ A $ is denoted as $ A_i $ , and $ i $ -th vertex of part $ B $ is denoted as $ B_i $ .
     
    For each index $ i (1 ≤ i < n) $ there is a directed edge from vertex $ A_i $ to vertex $ A_{i + 1} $ ,
    and from $ B_i $ to $ B_{i + 1} $ , respectively.
    Capacities of these edges are given in the input.
    Also there might be several directed edges going from part $ A $ to part $ B $ (but never from $ B $ to $ A $ ).
     
    You have to calculate the maximum flow value from $ A_1 $ to $ B_n $ in this network.
    Capacities of edges connecting $ A_i $ to $ A_{i + 1} $ might sometimes change,
    and you also have to maintain the maximum flow value after these changes.
    Apart from that, the network is fixed (there are no changes in part $ B $ ,
    no changes of edges going from $ A $ to $ B $ , and no edge insertions or deletions).
     
    Take a look at the example and the notes to understand the structure of the network better.
     

    Input

    The first line contains three integer numbers $ n, m $ and $ q (2 ≤ n, m ≤ 2·10^5, 0 ≤ q ≤ 2·10^5) $
    — the number of vertices in each part, the number of edges going from $ A $ to $ B $ and the number of changes, respectively.
     
    Then $ n - 1 $ lines follow, $ i $ -th line contains two integers $ x_i $ and $ y_i $ denoting
    that the edge from $ A_i $ to $ A_{i + 1} $ has capacity $ x_i $ and the edge from $ B_i $ to $ B_{i + 1} $ has capacity $ y_i (1 ≤ x_i, y_i ≤ 10^9) $ .
     
    Then $ m $ lines follow, describing the edges from $ A $ to $ B $ .
    Each line contains three integers $ x, y $ and $ z $ denoting an edge from $ A_x $ to $ B_y $ with capacity $ z (1 ≤ x, y ≤ n, 1 ≤ z ≤ 10^9) $ .
    There might be multiple edges from $ A_x $ to $ B_y $ .
     
    And then $ q $ lines follow, describing a sequence of changes to the network.
    $ i $ -th line contains two integers $ v_i $ and $ w_i $ , denoting that the capacity of the edge from $ A_{v_i} $ to $ A_{v_i + 1} $ is set to $ w_i (1 ≤ vi < n, 1 ≤ wi ≤ 10^9) $ .
     

    Output

    Firstly, print the maximum flow value in the original network.
    Then print $ q $ integers, $ i $ -th of them must be equal to the maximum flow value after $ i $ -th change.
     

    Examples

    input

     4 3 2
     1 2
     3 4
     5 6
     2 2 7
     1 4 8
     4 3 9
     1 100
     2 100
    

    output

     9
     14
     14
    

     

    Note

    This is the original network in the example:

    pic1

     

    题目翻译

    • 一张图分为两部分,左右都有 $ n $ 个节点,

    • $ A_i ightarrow A_{i+1} $ 连边, $ B_i ightarrow B_{i+1} $ 连边,容量给出

    • 有 $ m $ 对 $ A_i ightarrow B_j $ 有边,容量给出

    • 两种操作

    • 1.修改某条 $ A_i ightarrow A_{i+1} $ 的边的容量

    • 2.询问从 $ A_1 $ 到 $ B_n $ 的最大流

    • $ 2 le n,m le 2 imes 10^5 $ 流量 $ le 10^9 $

    感谢@yybyyb 提供的翻译
     

    思路

    • 因为最大流的流量等于最小割的容量,所以最大流不好做的时候考虑最小割。

    • 一些显而易见的结论:

    • 假如在 $ A $ 中,割掉 $ A_x $ 和 $ A_{x+1} $ 之间的有向边,
      那么割掉 $ A_y (y>x) $ 与 $ A_{y+1} $ 之间的有向边是没有意义的。

    • 假如在 $ B $ 中,割掉 $ B_X $ 和 $ B_{x+1} $ 之间的有向边,
      那么割掉 $ B_y (y>x) $ 与 $ B_{y+1} $ 之间的有向边是没有意义的。

    • 因此,在 $ A, B $ 中至多有一条边属于割集。

    • 假设在 $ A $ 中被割掉的边是 $ (A_x, A_{x+1}) $ ,在 $ B $ 中被割掉的边是 $ (B_y, B_{y+1}) $ ,
      那么任意 $ (A_u, B_v) (u ge x $ 且 $ v> y) $ 都是属于这个割集的。

    • 因此,割的大小可以看作三部分:在 $ A $ 中的割集大小,在 $ B $ 中的割集大小,在 $ A, B $ 间的割集大小。

    • 由于后两部分不会改变(只改 $ A $ 的边),考虑计算出它们。

    • 考虑在 $ A $ 中从小到大枚举 $ A_x $ ,表示割掉 $ A_x $ 和 $ A_{x+1} $ 之间的边, $ x=n $ 表示不存在这条边。

    • 那么下面要做的事情是在 $ B $ 中找到一个最优决策点 $ y $ ,使得后两部分的和最小。

    • 对于每加入一条 $ A, B $ 间的边,对答案造成的影响是连续的一段,从 $ 1 $ 开始。

    • 所以我们只需要写一个支持区间加,求 $ [1, n] $ 的最小值的线段树就好了。

    • 合并两部分的答案。这个可以用一个可删堆或者线段树来维护。

    • 时间复杂度 $ O((n+m+q)quad log_n ) $
       

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    #define int long long
    #define N 200005
    inline int read() {
        register char ch;
        while(!isdigit(ch=getchar()));
        register int x=ch^'0';
        while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
        return x;
    }
    vector<pair<int,int> >e[N];
    int n,m,q,a[N],b[N],c[N],sum[N<<2],lzy[N<<2];
    void build(int o,int l,int r,int p[]){
    	lzy[o]=0;
        if(l==r){
            sum[o]=p[l];
            return;
        }
        int mid=l+r>>1;
        build(o<<1,l,mid,p); build(o<<1|1,mid+1,r,p);
        sum[o]=min(sum[o<<1],sum[o<<1|1]);
    }
    void pushdown(int o){
        sum[o<<1]+=lzy[o];
        sum[o<<1|1]+=lzy[o];
        lzy[o<<1]+=lzy[o];
        lzy[o<<1|1]+=lzy[o];
        lzy[o]=0;
    }
    void updata(int o,int l,int r,int L,int R,int val){
        if(L<=l&&r<=R){
            sum[o]+=val;
            lzy[o]+=val;
            return;
        }
        if(lzy[o]) pushdown(o);
        int mid=l+r>>1;
        if(L>mid) updata(o<<1|1,mid+1,r,L,R,val);
        else if(R<=mid) updata(o<<1,l,mid,L,R,val);
        else {
            updata(o<<1,l,mid,L,R,val);
            updata(o<<1|1,mid+1,r,L,R,val);
        }
        sum[o]=min(sum[o<<1],sum[o<<1|1]);
    }
    signed main(){
        n=read(); m=read(); q=read();
        for(int i=1;i<n;++i){
            a[i]=read(); b[i+1]=read();
        }
        build(1,1,n,b);
        for(int i=1;i<=m;++i){
            int u,v,w;
            u=read(); v=read(); w=read();
            e[u].push_back(make_pair(v,w));
        }
        for(int i=1;i<=n;++i){
            for(int j=0;j<e[i].size();++j){
                int v=e[i][j].first,w=e[i][j].second;
                updata(1,1,n,1,v,w);
            }
            c[i]=sum[1]+a[i];
        }
        build(1,1,n,c);
        printf("%lld
    ",sum[1]);
        while(q--){
            int x,y; 
            x=read(); y=read();
            updata(1,1,n,x,x,y-a[x]);
            a[x]=y;
            printf("%lld
    ",sum[1]);
        }
        return 0;
    }
    /*
    #         42697120 
    When      2018-09-09 11:02:38 
    Who       PotremZ 
    Problem   G - Yet Another Maxflow Problem 
    Lang      GNU C++11
    Verdict   Accepted
    Time      467 ms
    Memory    24100 KB
    */
    
  • 相关阅读:
    安装VMware Workstation提示the msi failed的解决办法
    windows2008中没有右键个性化
    delphi调用AdoQuery实现SqlSever的存储过程(返回)
    delphi 如何解决假死
    用A4打印总账,预览及打印无表头。。
    解决VMWare“Could not get vmci driver version句柄无效”的错误
    第一章 认识jQuery
    jQuery $.each用法
    jquery ui tabs详解(中文)
    javascript面向对象
  • 原文地址:https://www.cnblogs.com/PotremZ/p/CF903G.html
Copyright © 2011-2022 走看看