• [USACO15DEC]最大流Max Flow(树上差分)


    题目描述:

    Farmer John has installed a new system of N−1N-1N−1 pipes to transport milk between the NNN stalls in his barn (2≤N≤50,0002 leq N leq 50,0002≤N≤50,000), conveniently numbered 1…N1 ldots N1…N. Each pipe connects a pair of stalls, and all stalls are connected to each-other via paths of pipes.

    FJ is pumping milk between KKK pairs of stalls (1≤K≤100,0001 leq K leq 100,0001≤K≤100,000). For the iiith such pair, you are told two stalls sis_isi and tit_iti, endpoints of a path along which milk is being pumped at a unit rate. FJ is concerned that some stalls might end up overwhelmed with all the milk being pumped through them, since a stall can serve as a waypoint along many of the KKK paths along which milk is being pumped. Please help him determine the maximum amount of milk being pumped through any stall. If milk is being pumped along a path from sis_isi to tit_iti, then it counts as being pumped through the endpoint stalls sis_isi and

    tit_iti, as well as through every stall along the path between them.

    FJ给他的牛棚的N(2≤N≤50,000)个隔间之间安装了N-1根管道,隔间编号从1到N。所有隔间都被管道连通了。

    FJ有K(1≤K≤100,000)条运输牛奶的路线,第i条路线从隔间si运输到隔间ti。一条运输路线会给它的两个端点处的隔间以及中间途径的所有隔间带来一个单位的运输压力,你需要计算压力最大的隔间的压力是多少。

    输入格式

    The first line of the input contains NNN and KKK.

    The next N−1N-1N−1 lines each contain two integers xxx and yyy (x≠yx e yx≠y) describing a pipe

    between stalls xxx and yyy.

    The next KKK lines each contain two integers sss and ttt describing the endpoint

    stalls of a path through which milk is being pumped.

    输出格式

    An integer specifying the maximum amount of milk pumped through any stall in the

    barn.

    输入输出样例

    输入 #1

    5 10
    3 4
    1 5
    4 2
    5 4
    5 4
    5 4
    3 5
    4 3
    4 3
    1 3
    3 5
    5 4
    1 5
    3 4
    

    输出 #1

    9
    

    思路:

    这里画一下样例的图就能比较明白题目的意思了。是这样的,题目给了一个图,再给k个询问,每次从一个点沿着原图的边到另一个点,k次询问后,问经过次数最多的点是哪一个。

    这样一讲,就想到了点的树上差分,假设从s点到t点,可以通过差分数组,使(dif[s]++,dif[t]++,dif[lca(s,t)]--,dif[f[lca(s,t)][0]]--),在统计每个点经过的次数,在回溯过程中求得最大值即可。

    实现上用了链式前向星,求lca得方法可参见上一篇博客。

    代码:

    #include <iostream>
    #include <cstdio>
    using namespace std;
    #define max_n 50005
    //前向星
    int head[max_n];
    struct edge
    {
        int v;
        int next;
    }e[max_n<<1];
    int cnt = 0;
    void add(int u,int v)
    {
        ++cnt;
        e[cnt].v = v;
        e[cnt].next = head[u];
        head[u] = cnt;
    }
    //读入优化
    inline void read(int& x)
    {
        x = 0;int f=0;char ch = getchar();
        while(ch<'0'||ch>'9') {if(ch=='-')f=1;ch=getchar();}
        while('0'<=ch&&ch<='9') {x = 10*x+ch-'0';ch=getchar();}
        x = f?-x:x;
    }
    //题目数据
    int n,k;
    int ans = 0;
    int f[max_n][23];
    int depth[max_n];
    int dif[max_n];//差分数组
    //求lca
    void dfs(int u,int from)
    {
        depth[u] = depth[from]+1;
        for(int i = 1;(1<<i)<=depth[u];i++)
        {
            f[u][i] = f[f[u][i-1]][i-1];
        }
        for(int i = head[u];i;i=e[i].next)
        {
            int v = e[i].v;
            if(from==v) continue;
            f[v][0] = u;
            dfs(v,u);
        }
    }
    int lca(int s,int t)
    {
        if(depth[s]<depth[t]) swap(s,t);
        for(int i = 20;i>=0;i--)
        {
            if(depth[f[s][i]]>=depth[t])
            {
                s =f[s][i];
            }
            if(s==t)
            {
                return s;
            }
        }
        for(int i = 20;i>=0;i--)
        {
            if(f[s][i]!=f[t][i])
            {
                s = f[s][i];
                t = f[t][i];
            }
        }
        return f[s][0];
    }
    //统计节点最大经过次数
    void maxsum(int u,int from)
    {
        for(int i = head[u];i;i=e[i].next)
        {
            int v = e[i].v;
            if(v==from) continue;
            maxsum(v,u);
            dif[u] += dif[v];
        }
        ans = max(ans,dif[u]);
    }
    
    int main()
    {
        read(n);read(k);
        //cout << "n " << n << " k " << k << endl;
        for(int i = 1;i<n;i++)
        {
            int u,v;
            read(u);
            read(v);
            add(u,v);
            add(v,u);
        }
        dfs(1,0);
        for(int i = 0;i<k;i++)
        {
            int u,v;
            read(u);
            read(v);
            int LCA = lca(u,v);
            dif[u]++;
            dif[v]++;
            dif[LCA]--;
            dif[f[LCA][0]]--;
        }
        maxsum(1,0);
        cout << ans << endl;
        return 0;
    }
    
    

    参考文章:

    顾z,差分数组 and 树上差分,https://rpdreamer.blog.luogu.org/ci-fen-and-shu-shang-ci-fen (洛谷出品!必属精品!,讲的虽然基础,但hin清晰)

    思结,树上差分的两种思路,https://www.luogu.org/blog/sincereactor/shu-shang-ci-fen-di-liang-zhong-sai-lu (同为洛谷博客,可对照参考)

  • 相关阅读:
    怎么安装Python?
    Ramnit蠕虫病毒分析和查杀
    Exphub[漏洞利用脚本库]
    SMBv3远程代码执行漏洞复现(CVE-2020-0796)
    Tomcat AJP 文件包含漏洞复现(CVE-2020-1938)
    Fastjson远程代码执行漏洞复现
    信息收集之——旁站、C段
    Redis未授权访问漏洞复现与利用
    CSS
    MVC控制器路由
  • 原文地址:https://www.cnblogs.com/zhanhonhao/p/11299945.html
Copyright © 2020-2023  润新知