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";
}```