题意
树上有一堆路径,问最多选择多少条路径使得每个点最多被一条路径覆盖
我们先把每条路径 \(u,v\) 的 lca 求出来记为 \(lca_{u,v}\),
然后我们来想一想,对于一个节点来说,选择怎样的一条路径才能让这条路径尽量不影响其他路径
我们就可以选择任意一条 lca位于这个点的路径,因为这样这条路径就不会影响到子树外的那些了,然后我们可以按照 lca 从深到浅的顺序来模拟,这样就一定保证是最优的,因为路径无权,一个点又只能被覆盖一次
// This code writed by chtholly_micromaker(MicroMaker)
#include <bits/stdc++.h>
#define reg register
#define int long long
using namespace std;
const int MaxN=100050;
struct Edge
{
int nxt,to;
}E[MaxN<<2];
struct Node
{
int a,b;
int lca;
}a[MaxN];
template <class t> inline void rd(t &s)
{
s=0;
reg char c=getchar();
while(!isdigit(c))
c=getchar();
while(isdigit(c))
s=(s<<3)+(s<<1)+(c^48),c=getchar();
return;
}
int hd[MaxN],en,n,m;
int up[MaxN][21],dep[MaxN];
bool vis[MaxN];
inline void adde(int u,int v)
{
++en;
E[en].nxt=hd[u];
E[en].to=v;
hd[u]=en;
return;
}
inline bool cmp(const Node &A,const Node &B)
{
return dep[A.lca]>dep[B.lca];
}
inline void dfs1(int u,int fa)
{
up[u][0]=fa;
for(int i=hd[u];~i;i=E[i].nxt)
{
reg int v=E[i].to;
if(v==fa)
continue;
dep[v]=dep[u]+1;
dfs1(v,u);
}
return;
}
inline void Init_lca()
{
for(int k=1;(1<<k)<=n;++k)
for(int i=1;i<=n;++i)
up[i][k]=up[up[i][k-1]][k-1];
return;
}
inline int lca(int u,int v)
{
if(dep[u]<dep[v])
swap(u,v);
if(dep[u]!=dep[v])
for(int k=20;k>=0;--k)
if(dep[up[u][k]]>=dep[v])
u=up[u][k];
if(u==v)
return u;
for(int k=20;k>=0;--k)
if(up[u][k]!=up[v][k])
u=up[u][k],v=up[v][k];
return up[u][0];
}
inline void work()
{
memset(hd,-1,sizeof hd);en=0;
memset(vis,false,sizeof vis);
reg int u,v,ans=0;
for(int i=1;i<n;++i)
{
scanf("%lld %lld",&u,&v);
adde(u,v);
adde(v,u);
}
dep[1]=1;
dfs1(1,1);
Init_lca();
for(int i=1;i<=m;++i)
{
scanf("%lld %lld",&a[i].a,&a[i].b);
a[i].lca=lca(a[i].a,a[i].b);
// printf("lca: %d , %d = %d\n",a[i].a,a[i].b,a[i].lca);
}
sort(a+1,a+m+1,cmp);
for(int i=1;i<=m;++i)
{
if(vis[a[i].lca])
continue;
reg bool flg=true;
for(int j=a[i].a;j!=a[i].lca;j=up[j][0])
if(vis[j])
{
flg=false;
break;
}
if(!flg)
continue;
flg=true;
for(int j=a[i].b;j!=a[i].lca;j=up[j][0])
if(vis[j])
{
flg=false;
break;
}
if(!flg)
continue;
++ans;
vis[a[i].lca]=true;
for(int j=a[i].a;j!=a[i].lca;j=up[j][0])
vis[j]=true;
for(int j=a[i].b;j!=a[i].lca;j=up[j][0])
vis[j]=true;
}
printf("%lld\n",ans);
return;
}
signed main(void)
{
while(~scanf("%lld %lld",&n,&m))
work();
return 0;
}
来源:https://www.cnblogs.com/chinesepikaync/p/12426081.html