1. 程式人生 > >題解 P3128 【[USACO15DEC]最大流Max Flow】

題解 P3128 【[USACO15DEC]最大流Max Flow】

題目描述

FJ給他的牛棚的N(2≤N≤50,000)個隔間之間安裝了N-1根管道,隔間編號從1到N。所有隔間都被管道連通了。

FJ有K(1≤K≤100,000)條運輸牛奶的路線,第i條路線從隔間si運輸到隔間ti。一條運輸路線會給它的兩個端點處的隔間以及中間途徑的所有隔間帶來一個單位的運輸壓力,你需要計算壓力最大的隔間的壓力是多少。

主要思路 : LCA + 樹上差分

如果您還不會差分,那就去這個神奇的網站去找一找差分吧(逃

這是道樹上差分裸題。

論如何樹上做差分,,,

還記得序列上差分是怎麼做的嗎\(QAQ\)

假如我們要把一段區間的資料+1,我們根據差的性質把左端點維護差分的陣列相應位置+1,右端點-1。

樹上差分也類似。我們只需要把兩個端點-1,兩個端點的lca -2,(為啥-2,emmm,因為有兩個端點要+1啊)。

但是這樣就會發現lca處求出的並沒有+1,我們可以使得lca處-1就好,保證之後的點加的時候會有+1的效果,我們在lca的父節點處也-1,保證lca處是有+1效果的。

所以就這麼搞啦!

code :

P.S. : (樹剖LCA打習慣了QAQ

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
using namespace std;
#define go(i, j, n, k) for(int i = j; i <= n; i += k)
#define fo(i, j, n, k) for(int i = j; i >= n; i -= k)
#define rep(i, x) for(int i = h[x]; i; i = e[i].nxt)
#define mn 100010
#define inf 1 << 30
#define ll long long
inline int read() {
    int x=0,f=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')f=-f;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x * f;
}
struct edge{
    int v, nxt;
}e[mn << 1];
int h[mn], p;
inline void add(int a, int b) {
    e[++p].nxt = h[a], h[a] = p, e[p].v = b;
}
int dep[mn], sze[mn], fa[mn], son[mn], top[mn], cnt, n, m, _minus[mn], ans = -1;
void dfs1(int x, int f, int deep) {
    dep[x] = deep;
    sze[x] = 1;
    fa[x] = f;
    int maxson = -1;
    rep(i, x) {
        int v = e[i].v;
        if(v == f) continue;
        dfs1(v, x, deep + 1);
        sze[x] += sze[v];
        if(sze[v] > maxson)
            maxson = sze[v], son[x] = v;
    }
}
void dfs2(int x, int topf) {
    top[x] = topf;
    if(!son[x]) return;
    dfs2(son[x], topf);
    rep(i, x) {
        int v = e[i].v;
        if(v == fa[x] || v == son[x]) continue;
        dfs2(v, v);
    }
}
inline int LCA(int x, int y) {
    while(top[x] != top[y]) {
        if(dep[top[x]] < dep[top[y]]) swap(x, y);
        x = fa[top[x]];
    }
    return dep[x] > dep[y] ? y : x;
}
inline void dfs(int x, int f) {
    rep(i, x) {
        int v = e[i].v;
        if(v == f) continue;
        dfs(v, x);
        _minus[x] += _minus[v];
    }
    ans = max(ans, _minus[x]);
}
int main() {
    n = read(), m = read();
    go(i, 1, n - 1, 1) {
        int a = read(), b = read();
        add(a, b), add(b, a);
    }
    dfs1(1, 0, 1); // 樹剖預處理的哦QAQ
    dfs2(1, 1);    // 樹剖預處理的哦QAQ
    go(i, 1, m, 1) {
        int a = read(), b = read(), lca = LCA(a, b);
        _minus[a]++, _minus[b]++, _minus[lca]--, _minus[fa[lca]]--; 
        // 不要問我的陣列變數名之前加‘_’,你可以試一下不加 
    }
    dfs(1, 0);     // 差分完了就做個樹上字首和就好辣!~\(≧▽≦)/~
    cout << ans << "\n";
    return 0;
}