P3128 [USACO15DEC]Max Flow P【树上差分_点差分(LCA)】

P3128 [USACO15DEC]Max Flow P


 题意

  • 一颗树,树上每个结点初始化点权为0. 有k次操作,每次操作对路径<u, v>上每个结点都进行加1操作。问:k次操作全部完成后,点权值最大的结点的点权为多少?

思路

  • 树上差分之点差分模板
  1. 无根树转有根树
  2. 对路径<u, v>操作时,++sum[u], ++sum[v], -- sum[lca(u, v)], --sum[fa[lca(u, v)]] 【即差分操作】
  3.  dfs整棵树,某个结点的点权等于以该结点为根的子树上的差分和 

  • 边差分: ++sum[u], ++sum[v], sum[lca(u, v)] -= 2
  • dfs跑完之后,sum[u]即为结点u到其父结点的边权

树上差分参考博客


#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;

typedef long long ll;

inline int read()
{
    int x = 0, f = 1; char c = getchar();
    while (c < '0' || c > '9') { if (c == '-') f = -f; c = getchar(); }
    while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
    return x * f;
}

const int maxN = 50004; //结点个数

int n, k;

struct EDGE{
    int adj, to;
    EDGE(int a = -1, int b = 0): adj(a), to(b) {}
}edge[maxN << 1];
int head[maxN], cnt;

void add_edge(int u, int v)
{
    edge[cnt] = EDGE(head[u], v);
    head[u] = cnt ++;
}

int f[maxN][20], deep[maxN];

void dfs(int u, int fa)
{
    deep[u] = deep[fa] + 1;
    f[u][0] = fa;
    for(int i = head[u]; ~i; i = edge[i].adj)
    {
        int v = edge[i].to;
        if(v == fa) continue;
        dfs(v, u);
    }
}

void pre()
{
    dfs(1, 0);
    for(int i = 1; i < 20; ++ i )
        for(int j = 1; j <= n; ++ j )
            f[j][i] = f[f[j][i - 1]][i - 1];
}

int LCA(int u, int v)
{
    if(deep[u] < deep[v]) swap(u, v);
    for(int i = 19; i >= 0; -- i )
    {
        if(deep[f[u][i]] >= deep[v])
            u = f[u][i];
    }
    if(u == v) return u;
    for(int i = 19; i >= 0; -- i )
    {
        if(f[u][i] != f[v][i])
        {
            u = f[u][i];
            v = f[v][i];
        }
    }
    return f[u][0];
}

int sum[maxN], ans;

void getAns(int u, int fa)
{
    for(int i = head[u]; ~i; i = edge[i].adj)
    {
        int v = edge[i].to;
        if(v == fa) continue;
        getAns(v, u);
        sum[u] += sum[v];
    }
    ans = max(ans, sum[u]);
}

int main()
{
    memset(head, -1, sizeof(head));
    n = read(); k = read();
    for(int i = 0; i < n - 1; ++ i )
    {
        int u, v; u = read(); v = read();
        add_edge(u, v);
        add_edge(v, u);
    }
    pre();
    for(int i = 0; i < k; ++ i )
    {
        int u, v; u = read(); v = read();
        int lca = LCA(u, v), fa = f[lca][0];
        ++ sum[u]; ++ sum[v];
        -- sum[lca]; -- sum[fa];
    }
    getAns(1, 0);
    printf("%d\n", ans);
    return 0;
}

QAQ,手瓢!把\n嫖成了\b....QAQ,所有样例全WA,亏我还找了半天bug  竟然没想到第一组测试样例是给出的样例QAQ

发布了242 篇原创文章 · 获赞 68 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_44049850/article/details/104594077