题目描述
FJ给他的牛棚的N(2≤N≤50,000)个隔间之间安装了N-1根管道,隔间编号从1到N。所有隔间都被管道连通了。
FJ有K(1≤K≤100,000)条运输牛奶的路线,第i条路线从隔间si运输到隔间ti。一条运输路线会给它的两个端点处的隔间以及中间途径的所有隔间带来一个单位的运输压力,你需要计算压力最大的隔间的压力是多少。
输入格式
输入的第一行包含N和K。
接下来的N-1行分别包含两个整数x和y(x≠y),用于描述管道在隔间x和隔间y。
之间有一条管道。
接下来有K行,每行包含两个整数s和t来描述牛奶运输路线的起点和终点。
输出格式
输出一个整数,即隔间最大压力的值。
输入输出样例
输入 #1复制
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
输出 #1复制
9
题目思想
,用倍增求LCA,再将差分转移到树上,处理后遍历累积答案即可.
由于这是点差分,设从
u
{u}
u到
v
{v}
v,
d
[
]
{d[]}
d[]为差分数组则有:
d
s
←
d
s
+
1
{d_s←d_s+1}
ds←ds+1
d
l
c
a
←
d
l
c
a
−
1
{d_{lca}←d_{lca}-1}
dlca←dlca−1
d
t
←
d
t
+
1
{d_t←d_t+1 }
dt←dt+1
d
f
(
l
c
a
)
←
d
f
(
l
c
a
)
−
1
{d_{f(lca)}←d_{f(lca)}-1}
df(lca)←df(lca)−1
即
d
[
u
]
+
+
,
d
[
v
]
+
+
;
{d[u]++,d[v]++;}
d[u]++,d[v]++;
d
[
L
C
A
(
u
,
v
)
]
−
−
,
d
[
f
a
[
L
C
A
(
u
,
v
)
]
]
−
−
{d[LCA(u,v)]--,d[fa[LCA(u,v)]]--}
d[LCA(u,v)]−−,d[fa[LCA(u,v)]]−−.
其原理同普通差分.
参考代码
#include<bits/stdc++.h>
#define N 100005
#define re register int
#define in read()
using namespace std;
int n,m;
int poww[N],fa[N][30];
int ans=-1;
int tot=0,fi[N],nxt[2*N],to[2*N];
int lg[N],dep[N];
inline int in{
int i=0;char ch;
while(!isdigit(ch)){ch=getchar();}
while(isdigit(ch)){i=(i<<3)+(i<<1)+(ch-'0');ch=getchar();}
return i;
}//快读
inline void lian(int u,int v)//邻接表
{
nxt[++tot]=fi[u];
to[tot]=v;
fi[u]=tot;
}
inline void Init(int u,int f)//LCA预处理
{
fa[u][0]=f;
dep[u]=dep[f]+1;
for(int i=1;i<=lg[dep[u]];i++)
fa[u][i]=fa[fa[u][i-1]][i-1];
for(int i=fi[u];i;i=nxt[i])
{
int v=to[i];
if(v==f)continue;
Init(v,u);
}
return;
}
inline int findLCA(int x,int y)//倍增求LCA
{
if(dep[x]<dep[y])swap(x,y);
while(dep[x]>dep[y])
x=fa[x][lg[dep[x]-dep[y]]-1];
if(x==y)return x;
for(int i=lg[dep[x]]-1;i>=0;i--)
{
if(fa[x][i]!=fa[y][i])
{
x=fa[x][i];
y=fa[y][i];
}
}
return fa[x][0];
}
inline void get_ans(int u,int f)
{
for(int i=fi[u];i;i=nxt[i])
{
int v=to[i];
if(v==f)continue;
get_ans(v,u);
poww[u]+=poww[v];
}
ans=max(ans,poww[u]);
}
int main()
{
int x,y,s,t;
n=in,m=in;
for(int i=1;i<=n;i++)//用于估计跳跃幅度,不加也可。
lg[i]=lg[i-1]+(1<<lg[i-1]==i);
for(int i=1;i<n;i++)//连边
{
x=in,y=in;
lian(x,y);
lian(y,x);
}
Init(1,0);//预处理
for(int i=1;i<=m;i++)//差分核心
{
s=in,t=in;
int ant=findLCA(s,t);
poww[s]++,poww[t]++;
poww[ant]--,poww[fa[ant][0]]--;
}
get_ans(1,0);//累加求答案
printf("%d\n",ans);
return 0;
}