洛谷P3128 [USACO15DEC] Max Flow P && 树上差分
传送门:P3128 [USACO15DEC] Max Flow P
题目意思:
给定一个节点数为 \(n\) 的树,有 \(m\) 次操作。
每次操作给你两个数 \(s\) 和 \(t\),你需要在 \(s\) 到 \(t\) 的路径所经过点的运输压力 \(+1\)。
求最后运输压力最大的点的压力。
思路:
发现 \(s\) 到 \(t\) 的路径为 \(s\to lca(s,t)\to t\)
那么我们可以建立一个差分数组 \(pres\)
每次操作在 \(s\to lca(s,t)\) 和 \(t\to lca(s,t)\) 的路径经过的点上 +1,就是 \(pres_s+1\),\(pres_t+1\),\(pres_{lca(s,t)}-2\)
问题:
但是这样 lca(s,t) 相当于并没有 +1,为了解决这个问题,我们来看一张图:
现在所有的 \(pres\) 都是 \(0\)
此时我们想从 \(3\) 走到 \(1\)
很明显他们的 \(lca\) 为 \(4\),按照上面的方法:我们能够得到:
这时开始遍历
void pressure(int now,int fa)
{
for(int i=fir[now];i;i=ed[i].next)
{
if(ed[i].v!=fa)
{
pressure(ed[i].v,now);
pres[now]+=pres[ed[i].v];
}
}
}
可以得到:
\(pres_1=1\),\(pres_5=1\),\(pres_3=1\),\(pres_4=0\),\(pres_2=0\),\(pres_7=0\),\(pres_6=0\)
观察到:pres_4 的值只会影响到他的父亲节点 6 的值,那么我们可以:
\(pres_4-1\),\(pres_6-1\)
这样就能得出正确答案了喵~
最终思路:
每次询问求 s 和 t 的 lca,\(pres_s+=1\),\(pres_t+=1\),\(pres_{lca(s,t)}-=1\),\(pres_{lca(s,t) 的 fa}-=1\)
最后遍历整棵树求最大值。
代码:
lca用的是倍增。
#include<bits/stdc++.h>
using namespace std;
const int maxn=50010;
const int maxm=100100;
int ans=-1;
int en;
int m,n;
int fir[maxn];
struct edge{
int v,next;
}ed[maxn*2];
void add_edge(int p1,int p2)
{
en++;
ed[en].v=p2;
ed[en].next=fir[p1];
fir[p1]=en;
}
int depth[maxn];
int f[maxn][25];
void dfs(int now,int fa)
{
depth[now]=depth[fa]+1;
f[now][0]=fa;
for(int i=1;i<=20;i++)
{
f[now][i]=f[f[now][i-1]][i-1];
}
for(int i=fir[now];i;i=ed[i].next)
{
if(ed[i].v!=fa) dfs(ed[i].v,now);
}
}
int get_lca(int a,int b)
{
if(depth[a]<depth[b]) swap(a,b);//让 a 成为深度更大的点
for(int i=20;i>=0;i--)
{
if(depth[f[a][i]] >= depth[b])
a=f[a][i];
}
if(a==b) return a;
for(int i=20;i>=0;i--)
{
if(f[a][i]!=f[b][i])
a=f[a][i],b=f[b][i];
}
return f[a][0];
}
int pres[maxn];
void pressure(int now,int fa)
{
for(int i=fir[now];i;i=ed[i].next)
{
if(ed[i].v!=fa)
{
pressure(ed[i].v,now);
pres[now]+=pres[ed[i].v];
}
}
ans=max(ans,pres[now]);
}
int main()
{
cin>>n>>m;
for(int i=1;i<n;i++)
{
int p1,p2;
cin>>p1>>p2;
add_edge(p1,p2);
add_edge(p2,p1);
}
dfs(1,0);
for(int i=1;i<=m;i++)
{
int s,e;
cin>>s>>e;
int lca=get_lca(s,e);
pres[s]++,pres[lca]--,pres[e]++,pres[f[lca][0]]--;
// cout<<lca<<endl;
}
pressure(1,0);cout<<ans<<endl;
return 0;
}