题目大意 :给定一个棵n个节点的树,给定树上m条路径的两个端点,求最多有多少条不相交的路径(两条路径没有公共顶点即为不相交)。
基本思路:比赛时没有做出来,没想到这个路径选择有贪心性质,贪心思想比较巧妙。首先将这颗树标记层次(我习惯从小到大),然后将每条路径的两个端点的最近公共祖先(也就等于是这条路径在这个标记了层次的树中层次最高的点)求出来,再按层次权值排序(将层次值最大的排在最前面),即可用贪心。每次选取一条路径后,将这条路径中的LCA点以下的所有点标记为已访问。
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = 100010;
struct Edge
{
int u,v,f,w;
Edge(){}
Edge(int x,int y,int z,int xx)
{
u=x,v=y,f=z,w=xx;
}
}edges[maxn];
vector<int >G[maxn];
int fa[maxn][20],d[maxn];
int n,m,vis[maxn],depth;
bool cmp(const Edge&a,const Edge &b)
{
return a.w>b.w;
}
void dfs(int u)
{
for (int i=0;i<G[u].size();i++){
int v=G[u][i];
if (!d[v])
{
d[v]=d[u]+1,fa[v][0]=u;
dfs(v);
if (d[v]>depth)
depth=d[v];
}
}
}
void bfs (int u)
{
vis[u]=1;
for (int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if (d[v]>d[u]&&!vis[v])
{
bfs(v);
}
}
}
int LCA(int p,int q)
{
int i,j;
if (d[p]<d[q])
{
int tem=p;
p=q;
q=tem;
}
for (i=0;(1<<i)<=d[p];i++);
for (j=i-1;j>=0;j--)
{
if (d[p]-(1<<j)>=d[q])
{
p=fa[p][j];
}
}
if (p==q)
return p;
for (j=i;j>=0;j--)
{
if (fa[p][j]!=fa[q][j])
{
p=fa[p][j];
q=fa[q][j];
}
}
return fa[p][0];
}
int main()
{
while (scanf("%d%d",&n,&m)!=EOF)
{
int i,j,u,v,ans=0;
depth=0;
memset(fa,-1,sizeof(fa));
for (i=1;i<=n;i++){
G[i].clear();
d[i]=0;
vis[i]=0;
}
for (i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
d[1]=1;
dfs(1);
for (j=1;(1<<j)<=depth;j++)
{
for (i=1;i<=n;i++)
{
int x=fa[i][j-1];
if (x!=-1)
{
fa[i][j]=fa[x][j-1];
}
}
}
for (i=0;i<m;i++){
scanf("%d%d",&u,&v);
int f=LCA(u,v);
edges[i]=Edge(u,v,f,d[f]);
}
sort(edges,edges+m,cmp);
for (i=0;i<m;i++)
{
if (!vis[edges[i].u]&&!vis[edges[i].v])
{
if (!vis[edges[i].f])
bfs(edges[i].f);
ans++;
}
}
printf("%d\n",ans);
}
return 0;
}