bzoj4390: [Usaco2015 dec]Max Flow

本文介绍了一道关于树上差分的经典算法题,通过给定的树结构和操作,求解经过一系列路径上的点权增加操作后最大的点权值。文章详细解释了如何找到路径上的最低公共祖先(LCA),并利用差分思想更新节点值,最终通过递归获取每个节点的实际权值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题面在这里

题意:

给一棵树,k个操作,每次将u-v的路径上的点权都加一。
问最后最大的点权。

做法:

树上差分裸题= =
找u-v的lca,然后将路径上的点+1相当于c[u]++,c[v]++,c[lca]–,c[fa[lca]]–.
c[]是差分数组。

代码:

/*************************************************************
    Problem: bzoj 4390 [Usaco2015 dec]Max Flow
    User: fengyuan
    Language: C++
    Result: Accepted
    Time: 1852 ms
    Memory: 7112 kb
    Submit_Time: 2018-01-02 16:13:23
*************************************************************/

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;

const int N = 50010;
int n, m, cnt, ans;
int head[N], depth[N], f[N][20], c[N];
struct Edge{ int to, nex; }e[N<<1];

inline void add(int x, int y){ e[++ cnt].to = y; e[cnt].nex = head[x]; head[x] = cnt; }
inline void dfs(int u, int lst, int s)
{
    depth[u] = s; f[u][0] = lst;
    for(int i = head[u]; i; i = e[i].nex) {
        int v = e[i].to; if(v == lst) continue;
        dfs(v, u, s+1);
    }
}
inline int LCA(int x, int y)
{
    if(depth[x] < depth[y]) swap(x, y);
    int tmp = depth[x] - depth[y];
    for(int i = 17; i >= 0; i --)
        if(tmp>>i&1) x = f[x][i];
    if(x == y) return x;
    for(int i = 17; i >= 0; i --)
        if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
    return f[x][0];
}
inline void dfs2(int u, int lst)
{
    for(int i = head[u]; i; i = e[i].nex) {
        int v = e[i].to; if(v == lst) continue;
        dfs2(v, u); c[u] += c[v];
    }
    ans = max(ans, c[u]);
}
int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i < n; i ++) {
        int x, y; scanf("%d%d", &x, &y);
        add(x, y); add(y, x);
    } dfs(1, 0, 0);
    for(int j = 1; j <= 17; j ++)
        for(int i = 1; i <= n; i ++) f[i][j] = f[f[i][j-1]][j-1];
    while(m --) {
        int x, y, z; scanf("%d%d", &x, &y);
        z = LCA(x, y);
        c[x] ++; c[y] ++; c[z] --; c[f[z][0]] --;
    }
    dfs2(1, 0);
    printf("%d\n", ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值