题解 P3128 【[USACO15DEC]最大流Max Flow】
Segmentree · · 题解
-
首先,我们通过阅读题干的建边不难发现这道题是以树形结构为背景的。
-
继续往下看:给定两个隔间u,v,使得u->v这条路径上的所有隔间的压力(点权)加一,小脑瓜
疯狂转动,这不是区间修改吗!那么是时候运用蒟蒻我唯一会的修改区间算法———差分了!
我们提取这两段的两个关键词 “树形结构”,“差分”,巴啦啦摸仙全身变 树上差分!
因此这道题的思路就非常清晰了:
建树- 树上差分(用lca辅助其实现,如果还有对lca不熟的同学可以前往P3379 【模板】最近公共祖先(LCA)理解一下这个在树上巨有用的算法)
Code:
/*Coded By Lxhao*/
/*Full Of Stars*/
#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;
#define re register
#define r(x) x=read()
#define c getchar()
#define ll long long
inline int read()
{
int w=1,s=0;
char ch=c;
while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=c;}
while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+ch-'0',ch=c;
return s*w;
}
const int maxn=5e4+10;
int n,k,cnt,x,y,fnl;
int f[maxn][21],depth[maxn],head[maxn],sum[maxn];
//f[i][j]表示以i为起点往上跳2^j个点,depth表示深度,sum为前缀和数组
struct node
{
int to,next,dis;
}edge[maxn<<1];
inline void add(int from,int to)
{
edge[++cnt].next=head[from];
edge[cnt].to=to;
head[from]=cnt;
}
inline int max(int a,int b){return a>b?a:b;}
inline void dfs(int u,int fa)
{
f[u][0]=fa;//2^0=1,所以f[u][0]存的是他的父亲节点
depth[u]=depth[fa]+1;//叶子结点的深度比父亲节点大一
for(re int i=1;(1<<i)<=depth[u];++i)f[u][i]=f[f[u][i-1]][i-1];//往上跳(倍增思想)
for(re int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(v!=fa) dfs(v,u);
}
}//建树
inline int lca(int u,int v)
{
if(depth[u]<depth[v])swap(u,v);
for(re int i=20;i>=0;--i)
{
if((1<<i)<=depth[u]-depth[v])
u=f[u][i];
}//u为深度较深的一点,先跳u使u,v达到同一深度
if(u==v) return u;
for(re int i=20;i>=0;--i)
{
if(f[u][i]!=f[v][i])
{
u=f[u][i];
v=f[v][i];
}
}//达到同一深度后一起跳
return f[u][0];
}
inline void Gmax(int u,int fa)
{
for(re int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(v!=fa)
{
Gmax(v,u);
sum[u]+=sum[v];
}
}
fnl=max(fnl,sum[u]);
}//用dfs来求以树为基础的查分数组的最大值
int main()
{
r(n),r(k);
for(re int i=1,u,v;i<=n-1;++i)
{
r(u),r(v);
add(u,v),add(v,u);
}//建双向边
dfs(1,0);
for(;k;k--)
{
r(x),r(y);
int fa=lca(x,y);
++sum[x],++sum[y];
--sum[fa],--sum[f[fa][0]];
}//树上差分修改区间值
Gmax(1,0);//求最值
printf("%d",fnl);
}
谢谢观看,如有不足请多指出qwq