HYSBZ - 4390(Max Flow 树上差分)

本文深入探讨了树上差分的概念及其在MaxFlow问题中的应用,通过实例讲解了边差分和点差分的方法,以及如何在树形结构中高效地更新和查询路径上的元素出现次数。附带的模板题和代码示例帮助读者理解并实践这一算法技巧。

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

HYSBZ - 4390(Max Flow 树上差分)

先说下差分数组的思想

边差分

即快速统计出每条边在我们执行的操作中出现的次数。
len[i]表示i号点到它的父亲的那条边出现的次数。
假设接下来我们对x−>y这条路径执行了某个操作,需要修改这条路径上的每条边出现的次数。
我们只需要维护这条路径的两端与lca即可:

len[x]++,len[y]++,len[lca(x,y)]-=2;

最后我们只需要从根节点开始遍历图就好了

点差分

与边差分类似,快速统计出每个点在我们执行的操作中出现的次数
len[i]表示i号点出现的次数。
假设接下来我们对x−>y 这条路径执行了某个操作,需要修改这条路径上的每条边出现的次数。
我们只需要维护这条路径的两端与lca lcalca与之父亲即可:
len[x]++, len[y]++, len[lca(x,y)], len[fa[lca(x,y)][0]]
最后依然遍历一遍图。
————————————————
感谢大佬博客
原文链接:https://blog.youkuaiyun.com/yanzhenhuai/article/details/82945157

树上差分和差分数组的思想类似 区间修改只需要更改几个端点,查询时遍历一遍图即可

附上一道模板题
题目描述
Farmer John has installed a new system of N−1 pipes to transport milk between the N stalls in his barn (2≤N≤50,000), conveniently numbered 1…N. Each pipe connects a pair of stalls, and all stalls are connected to each-other via paths of pipes.
FJ is pumping milk between KK pairs of stalls (1≤K≤100,000). For the iith such pair, you are told two stalls sisi and titi, endpoints of a path along which milk is being pumped at a unit rate. FJ is concerned that some stalls might end up overwhelmed with all the milk being pumped through them, since a stall can serve as a waypoint along many of the KK paths along which milk is being pumped. Please help him determine the maximum amount of milk being pumped through any stall. If milk is being pumped along a path from sisi to titi, then it counts as being pumped through the endpoint stalls sisi and titi, as well as through every stall along the path between them.
给定一棵有N个点的树,所有节点的权值都为0。
有K次操作,每次指定两个点s,t,将s到t路径上所有点的权值都加一。
请输出K次操作完毕后权值最大的那个点的权值。
输入
The first line of the input contains NN and KK.
The next N−1 lines each contain two integers x and y (x≠y,x≠y) describing a pipe between stalls x and y.
The next K lines each contain two integers ss and t describing the endpoint stalls of a path through which milk is being pumped.
输出
An integer specifying the maximum amount of milk pumped through any stall in the barn.
样例输入
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
样例输出
9

模板题可以直接用
点修改,之后查询所有点权值最大值

//#pragma GCC optimize(3,"Ofast","inline")  	//G++
#pragma comment(linker, "/STACK:102400000,102400000")
#pragma GCC optimize(2)
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include <cstdlib>
#include <functional>
#define TEST freopen("in.txt","r",stdin);
using namespace __gnu_cxx;
#define mem(a,x) memset(a,x,sizeof(a))
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include <ext/hash_map>     	//hashmap
using namespace std;
typedef long long ll;
typedef unsigned long long ull; // %llu
const double PI = acos(-1.0);
const double eps = 1e-6;
const int mod=1e9+7;
const int INF = -1u>>1;
const int maxn = 5e5+5;
int n,q,root,ans;
struct Edge
{
    int l,r;
} p[maxn];
int father[maxn][30],depth[maxn],len[maxn];
vector<int>edge[maxn];
void add(int a,int b)
{
    edge[a].push_back(b);
    edge[b].push_back(a);
}
void dfs(int u,int fa)
{
    depth[u]=depth[fa]+1;
    father[u][0]=fa;
    len[u]=0;
    for(int i=1; (1<<i)<=depth[u]; i++)
    {
        father[u][i]=father[father[u][i-1]][i-1];
    }
    for(int i=0; i<edge[u].size(); i++)
    {
        int v=edge[u][i];
        if(v!=fa)
        {
            dfs(v,u);
        }
    }
}
int LCA(int x,int y)
{
    if(depth[x]<depth[y]) swap(x,y);
    for(int i=20; i>=0; i--)
    {
        if(depth[father[x][i]]>=depth[y])
            x=father[x][i];
        if(depth[x]==depth[y])
            break;
    }
    if(x==y) return x;
    for(int i=20; i>=0; i--)
    {
        if(father[x][i]!=father[y][i])
        {
            x=father[x][i];
            y=father[y][i];
        }
    }
    return father[x][0];
}
void solve(int u,int fa)
{
    for(int i=0; i<edge[u].size(); i++)
    {
        int v=edge[u][i];
        if(v!=fa)
        {
            solve(v,u);
            len[u]+=len[v];
            ans=max(ans,len[u]);
        }
    }
}
int main()
{
//    TEST
    ios;
    cin>>n>>q;
    for(int i=1; i<=n-1; i++)
    {
        cin>>p[i].l>>p[i].r;
        add(p[i].l,p[i].r);
        root=p[i].l;
    }
    dfs(root,0);
    while(q--)
    {
        int x,y;
        cin>>x>>y;
        len[x]++;
        len[y]++;
        int lca=LCA(x,y);
        len[lca]--;
        len[father[lca][0]]--;
    }
    solve(root,0);
    cout<<ans<<"\n";
}```

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值