传送门
倍增求LCA+树上差分
典型的树上差分题,根据书上差分的思想,w[u]和w[v]分别加1,它们的最近公共祖先(LCA)和LCA的父亲各减1,最后dfs求和。
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
#define mems(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=5e4+30;
int head[N],d[N],pa[N][25],dis[N],cnt[N];
int tot;
struct node{
int v,next;
}s[N*2];
void add(int u,int v)
{
s[tot].v=v;
s[tot].next=head[u];
head[u]=tot++;
}
void init()
{
tot=0;
mems(head,-1);
mems(d,0);
mems(dis,0);
mems(pa,0);
}
void dfs1(int u,int fa,int len)
{
d[u]=d[fa]+1;//深度
dis[u]=len;//到根节点距离
pa[u][0]=fa;
for(int i=1;(1<<i)<=d[u];i++)
{
pa[u][i]=pa[pa[u][i-1]][i-1];
}
for(int i=head[u];~i;i=s[i].next)
{
int v=s[i].v;
if(v!=fa)
dfs1(v,u,len+1);
}
}
int lca(int a,int b)
{
if(d[a]>d[b])
swap(a,b);
for(int i=20;i>=0;i--)
{
if(d[a]<=d[b]-(1<<i))
b=pa[b][i];
}
if(a==b)
{
return a;
}
for(int i=20;i>=0;i--)
{
if(pa[a][i]==pa[b][i])
continue;
else
{
a=pa[a][i];
b=pa[b][i];
}
}
return pa[a][0];
}
void dfs2(int u,int fa)
{
for(int i=head[u];~i;i=s[i].next)
{
int v=s[i].v;
if(v==fa)
continue;
dfs2(v,u);
cnt[u]+=cnt[v];
}
}
int main()
{
int n,k;
init();
scanf("%d%d",&n,&k);
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
dfs1(1,0,0);
for(int i=0;i<k;i++)
{
int u,v;
scanf("%d%d",&u,&v);
int c=lca(u,v);
cnt[u]++,cnt[v]++;
cnt[c]--;cnt[pa[c][0]]--;
}
dfs2(1,0);
int ans=0;
for(int i=1;i<=n;i++)
ans=max(ans,cnt[i]);
printf("%d\n",ans);
return 0;
}