http://acm.hdu.edu.cn/showproblem.php?pid=4912
题目
有一棵树,顶点为1,2,3…n,树上有m条路径,选择一些路径,且这些路径没有公共部分。问最大路径数
题解
- 算出每一条路径的两个顶点的最近公共祖先,从大到小排序
- 按顺序遍历一遍即可
#include<bits/stdc++.h>
using namespace std;
int head[100010],cnt,p[100010][20],d[100010],n,m,vis[100010];
struct node
{
int next,to;
} a[1000010];
struct noo
{
int u,v,lca;
} b[100100];
void add(int u,int v)
{
cnt++;
a[cnt].next=head[u];
a[cnt].to=v;
head[u]=cnt;
}
void ddd(int u,int fa)
{
int i,v;
p[u][0]=fa;
for(i=1; i<20; i++) p[u][i]=p[p[u][i-1]][i-1];
for(i=head[u]; i!=-1; i=a[i].next)
{
v=a[i].to;
if(v==fa) continue;
p[v][0]=u;
d[v]=d[u]+1;
ddd(v,u);
}
}
bool cmp(noo x,noo y)
{
return d[x.lca]>d[y.lca];
}
int LCA(int x,int y)
{
int i;
if(d[x]<d[y])swap(x,y);
for(i=19; i>=0; i--)
if( (1<<i)&(d[x]-d[y]) )
x=p[x][i];
if(x==y) return x;
for(i=19; i>=0; i--)
if(p[x][i]!=p[y][i])
x=p[x][i],y=p[y][i];
return p[x][0];
}
int main()
{
freopen("a.txt","r",stdin);
int i,x,y,ans,u,v,lca,j;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(head,-1,sizeof(head));
cnt=0;
for(i=1; i<n; i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
d[1]=0;
ddd(1,1);
for(i=1; i<=m; i++)
{
scanf("%d%d",&b[i].u,&b[i].v);
b[i].lca=LCA(b[i].u,b[i].v);
}
sort(b+1,b+m+1,cmp);
memset(vis,0,sizeof(vis));
ans=0;
for(i=1; i<=m; i++)
{
x=0;
u=b[i].u;
v=b[i].v;
lca=b[i].lca;
if(vis[u]||vis[v]||vis[lca]) continue;
for(j=u; j!=lca; j=p[j][0])
if(vis[j])
{
x=1;
break;
}
for(j=v; j!=lca; j=p[j][0])
if(vis[j])
{
x=1;
break;
}
if(x==1) continue;
ans++;
vis[lca]=1;
for(j=u; j!=lca; j=p[j][0]) vis[j]=1;
for(j=v; j!=lca; j=p[j][0]) vis[j]=1;
}
printf("%d\n",ans);
}
return 0;
}