【树上差分】P3128 [USACO15DEC]Max Flow P
-
题意
FJ给他的牛棚的N个隔间之间安装了N-1根管道,隔间编号从1到N。所有隔间都被管道连通了。
FJ有K条运输牛奶的路线,第i条路线从隔间si运输到隔间ti。一条运输路线会给它的两个端点处的隔间以及中间途径的所有隔间带来一个单位的运输压力,你需要计算压力最大的隔间的压力是多少。
隔间\(s_i\)到\(lca(s_i,t_i)\),再到\(t_i\)这条路径上所有的点的值都要进行加1操作。
而如果直接沿着这条路径对每一个结点进行+1操作,那是一个非常巨大的工作量。
于是可以借助差分的思想和dfs的特性来只对四个点进行修改,一个是\(t_i\),另外一个是\(s_i\),再一个是\(lca(t_i,s_i)\),还有一个是\(fa(lca(t_i,s_i))\)
前两者进行加一标记,后两者进行减一操作,对lca进行减一是因为多算了一个,对lca的父亲结点进行减一是因为取消这条链上的影响
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define MAX 1000005
#define MOD 1000000007
#define PB push_back
using namespace std;
const int N = 5E4+500,logs = 18;
int n,m,k;
vector<int > g[N];
int dep[N],fa[N][logs+2],val[N];
void pre_dfs(int u,int from)
{
dep[u] = dep[from] + 1 , fa[u][0] = from;
for(int i = 0;fa[u][i];i++) fa[u][i+1] = fa[ fa[u][i] ][i];
for(auto v:g[u])
{
if(v==from) continue;
pre_dfs(v,u);
}
}
int get_lca(int lowu,int u)
{
if(dep[lowu]<dep[u]) swap(lowu,u);
for(int i = logs;i>=0;i--) if(dep[lowu]-(1<<i)>=dep[u]) lowu = fa[lowu][i];
if(lowu==u) return u;
for(int i=logs;i>=0;i--) if(fa[lowu][i]!=fa[u][i]) lowu = fa[lowu][i],u = fa[u][i];
return fa[u][0];
}
int ans;
void get_ans(int u,int from)
{
for(auto v:g[u])
{
if(v==from) continue;
get_ans(v,u);
val[u] += val[v];
}
ans = max(ans,val[u]);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>k;
repd(i,1,n-1)
{
int u,v;
cin>>u>>v;
g[u].PB(v),g[v].PB(u);
}
pre_dfs(1,0);
repd(i,1,k)
{
int u,v;
cin>>u>>v;
int lca = get_lca(u,v);
val[u]++,val[v]++,val[lca]--,val[ fa[lca][0] ]--;
}
get_ans(1,0);
cout<<ans;
return 0;
}