题意
树上有一堆路径,问最多选择多少条路径使得每个点最多被一条路径覆盖
我们先把每条路径 \(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