HDU 4912 Paths on the tree

http://acm.hdu.edu.cn/showproblem.php?pid=4912

题目

有一棵树,顶点为1,2,3…n,树上有m条路径,选择一些路径,且这些路径没有公共部分。问最大路径数

题解
  1. 算出每一条路径的两个顶点的最近公共祖先,从大到小排序
  2. 按顺序遍历一遍即可
#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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值