洛谷 P3128 [USACO15DEC] Max Flow P -普及+/提高

P3128 [USACO15DEC] Max Flow P

题目描述

Farmer John 在他的谷仓中安装了 N−1N-1N−1 条管道,用于在 NNN 个牛棚之间运输牛奶(2≤N≤50,0002 \leq N \leq 50,0002≤N≤50,000),牛棚方便地编号为 1...N1 \ldots N1...N。每条管道连接一对牛棚,所有牛棚通过这些管道相互连接。

FJ 正在 KKK 对牛棚之间泵送牛奶(1≤K≤100,0001 \leq K \leq 100,0001≤K≤100,000)。对于第 iii 对牛棚,你被告知两个牛棚 sis_isi 和 tit_iti,这是牛奶以单位速率泵送的路径的端点。FJ 担心某些牛棚可能会因为过多的牛奶通过它们而不堪重负,因为一个牛棚可能会作为许多泵送路径的中转站。请帮助他确定通过任何一个牛棚的最大牛奶量。如果牛奶沿着从 sis_isi 到 tit_iti 的路径泵送,那么它将被计入端点牛棚 sis_isi 和 tit_iti,以及它们之间路径上的所有牛棚。

输入格式

输入的第一行包含 NNN 和 KKK。

接下来的 N−1N-1N−1 行每行包含两个整数 xxx 和 yyy(x≠yx \ne yx=y),描述连接牛棚 xxx 和 yyy 的管道。

接下来的 KKK 行每行包含两个整数 sss 和 ttt,描述牛奶泵送路径的端点牛棚。

输出格式

输出一个整数,表示通过谷仓中任何一个牛棚的最大牛奶量。

输入输出样例 #1

输入 #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

说明/提示

2≤N≤5×104,1≤K≤1052 \le N \le 5 \times 10^4,1 \le K \le 10^52≤N≤5×104,1≤K≤105。

solution

  • 1 对于一条路径 x -> y. 设 lca(A, B) = u, 则 u -> x 和 u -> y 所有节点次数 +1,但是u重复了一次
复制代码
   如果 u = x (或者y) 也可以这么处理
  • 2 对于 1 中可以标记 g[x]++, g[y]++, g[u]--, g[fa[u]]--,然后从下往上求前缀和即可

代码

cpp 复制代码
#include <iostream>
#include "bit"
#include "vector"
#include "unordered_set"
#include "set"
#include "queue"
#include "algorithm"
#include "bitset"
#include "cstring"

using namespace std;

/*
 * P3128 [USACO15DEC] Max Flow P
 * 题目大意: n (n <= 50000) 个节点组成一颗树, k (<=10^5) 条路径,求每个顶点被路径通过的次数的最大值
 *
 * 思路:树上差分+最近公共祖先
 * 1 对于一条路径 x -> y. 设 lca(A, B) = u, 则 u -> x 和 u -> y 所有节点次数 +1,但是u重复了一次
 *      如果 u = x (或者y) 也可以这么处理
 * 2 对于 1 中可以标记 g[x]++, g[y]++, g[u]--, g[fa[u]]--,然后从下往上求前缀和即可
 */

const int N = 5e4 + 1;

int n, K, d[N], f[N][20], g[N], ans;
vector<int> e[N];

void dfs(int u, int p) {
    f[u][0] = p;
    for (int i = 1; i < 20; i++) f[u][i] = f[f[u][i - 1]][i - 1];
    d[u] = d[p] + 1;
    for (int v: e[u]) if (v != p) dfs(v, u);
}

void dfs2(int u, int p) {
    for (int v: e[u])
        if (v != p) {
            dfs2(v, u);
            g[u] += g[v];
        }
    ans = max(ans, g[u]);
}

int lca(int x, int y) {
    if (x == y) return x;
    if (d[x] < d[y]) swap(x, y);
    for (int i = 19; d[x] != d[y]; i--) if (d[f[x][i]] >= d[y]) x = f[x][i];

    if (x == y) return x;
    for (int i = 19; i >= 0; i--) if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];

    return f[x][0];
}

int main() {
    cin >> n >> K;

    for (int i = 1; i < n; i++) {
        int x, y;
        cin >> x >> y;
        e[x].push_back(y);
        e[y].push_back(x);
    }

    dfs(1, 0);

    for (int i = 0, x, y; i < K; i++) {
        cin >> x >> y;
        int u = lca(x, y);
        g[x]++, g[y]++, g[u]--, g[f[u][0]]--;
    }

    dfs2(1, 0);
    cout << ans << endl;

    return 0;
}

结果

相关推荐
草莓熊Lotso28 分钟前
Linux 基础 IO 初步解析:从 C 库函数到系统调用,理解文件操作本质
linux·运维·服务器·c语言·数据库·c++·人工智能
梵刹古音28 分钟前
【C语言】 字符数组相关库函数
c语言·开发语言·算法
闻缺陷则喜何志丹31 分钟前
P8699 [蓝桥杯 2019 国 B] 排列数|普及+
c++·数学·蓝桥杯·数论·洛谷·数列
D_evil__6 小时前
【Effective Modern C++】第三章 转向现代C++:16. 让const成员函数线程安全
c++
wfeqhfxz25887827 小时前
YOLO13-C3k2-GhostDynamicConv烟雾检测算法实现与优化
人工智能·算法·计算机视觉
Aaron15888 小时前
基于RFSOC的数字射频存储技术应用分析
c语言·人工智能·驱动开发·算法·fpga开发·硬件工程·信号处理
Queenie_Charlie8 小时前
前缀和的前缀和
数据结构·c++·树状数组
kokunka9 小时前
【源码+注释】纯C++小游戏开发之射击小球游戏
开发语言·c++·游戏
_不会dp不改名_9 小时前
leetcode_3010 将数组分成最小总代价的子数组 I
算法·leetcode·职场和发展
John_ToDebug11 小时前
浏览器内核崩溃深度分析:从 MiniDump 堆栈到 BindOnce UAF 机制(未完待续...)
c++·chrome·windows