592D:Super M
題意簡述
給出一棵
樹上相鄰節點距離爲
你被要求從任意點出發,遍歷這些標記節點,求最小的總路程。
數據範圍
思路
樹形DP。
最優的方案肯定是沿着DFS序走。
每DFS到一個標記節點,就把沿路往上的路徑算兩遍加入貢獻直到另一個標記節點。
因爲我們不必回到起點,所有再做一次DFS,求出標記節點之間的最遠距離,減到答案裏。
這一步我們可以用類似樹的直徑的方法DFS兩次。
代碼
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
struct Node{
int s,t,next;
}e[250010];
int head[130010],cnt;
void addedge(int s,int t)
{
e[cnt].s=s;e[cnt].t=t;e[cnt].next=head[s];head[s]=cnt++;
e[cnt].s=t;e[cnt].t=s;e[cnt].next=head[t];head[t]=cnt++;
}
bool pd[130010],lable[130010];
int dis[130010];
int n,m,u,v,pos,ans,tmp;
void dfs(int node,int lastfa)
{
pd[node]=lable[node];
for (int i=head[node];i!=-1;i=e[i].next)
if (e[i].t!=lastfa)
{
dfs(e[i].t,node);
if (pd[e[i].t])
ans+=2;
pd[node]|=pd[e[i].t];
}
}
void dfs2(int node,int lastfa,int sum)
{
dis[node]=sum;
for (int i=head[node];i!=-1;i=e[i].next)
if (e[i].t!=lastfa)
dfs2(e[i].t,node,sum+1);
}
int main()
{
scanf("%d%d",&n,&m);
memset(head,0xff,sizeof(head));
cnt=0;
for (int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
addedge(u,v);
}
for (int i=1;i<=m;i++)
{
scanf("%d",&u);
lable[u]=1;
}
dfs(u,u);
dis[0]=-1;
dfs2(u,u,0);
for (int i=1;i<=n;i++)
if (lable[i]&&dis[i]>dis[pos])
pos=i;
tmp=pos;
dfs2(pos,pos,0);
pos=0;
for (int i=1;i<=n;i++)
if (lable[i]&&dis[i]>dis[pos])
pos=i;
ans=ans-dis[pos];
pos=min(pos,tmp);
printf("%d\n%d\n",pos,ans);
return 0;
}