「LCA + 树上差分」[USACO15DEC]最大流Max Flow

孤街醉人 提交于 2020-02-10 05:00:55

[USACO15DEC]最大流Max Flow

原题链接 最大流Max Flow

题目大意

给你 \(n - 1\) 条边,再给你 \(m\) 个操作,每次操作两个数 \(u, v\) 表示,\(u, v\) 的最短路径上每个点都加上\(1\)

题目题解

树上差分的经典题 (一直想学树上差分,今天终于会了quq),我们修改时,使\(power_u\)++ ,\(power_v\)++,\(power_{lca(u,v)}\)--,\(power_{f[lca(u,v)][0]}\)-- 就可以了

接下来就是代码..xx

//#define fre yes

#include <cstdio>
#include <cstring>
#include <iostream>

int n, m;
const int N = 50005;
int head[N << 1], to[N << 1], ver[N << 1];
int f[N][22], lg[N], depth[N], power[N];

int tot;
void addedge(int x, int y) {
    ver[tot] = y;
    to[tot] = head[x];
    head[x] = tot++;
}

void dfs(int x, int fa) {
    depth[x] = depth[fa] + 1;
    f[x][0] = fa;
    for (int i = 1; (1 << i) <= depth[x]; i++) {
        f[x][i] = f[f[x][i - 1]][i - 1];
    }

    for (int i = head[x]; ~i; i = to[i]) {
        int v = ver[i];
        if(v != fa) {
            dfs(v, x);
        }
    }
}

int ans;
void sum(int u, int fa) {
    for (int i = head[u]; ~i; i = to[i]) {
        int v = ver[i];
        if(v != fa) {
            sum(v, u);
            power[u] += power[v];
        }
    } ans = std::max(ans, power[u]);
}

int lca(int u, int v) {
    if(depth[u] < depth[v]) {
        std::swap(u, v);
    }

    while(depth[u] > depth[v]) {
        u = f[u][lg[depth[u] - depth[v]] - 1];
    }

    if(u == v) return u;

    for (int i = lg[depth[u]] - 1; i >= 0; i--) {
        if(f[u][i] != f[v][i]) {
            u = f[u][i];
            v = f[v][i];
        }
    } return f[u][0];
}

int main() {
    memset(head, -1, sizeof(head));
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n - 1; i++) {
        int u, v;
        scanf("%d %d", &u, &v);
        addedge(u, v);
        addedge(v, u);
    }

    dfs(1, -1);

    for (int i = 1; i <= n; i++) {
        lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
    }

    for (int i = 1; i <= m; i++) {
        int x, y;
        scanf("%d %d", &x, &y);
        int lc = lca(x, y);
        ++power[x]; ++power[y]; --power[lc]; --power[f[lc][0]];
    }

    sum(1, -1);

    printf("%d\n", ans);
    return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!