Super M ~~
題意: 從一個點出發,必須經過給出的k個點,求最短的路,並且最短路有多條則開始點字典序最小
首先,我們知道從必須經過的點出發總是比從其他點出發要短,再者最好不經過一條邊兩次,三次以上就沒意義了,則我們首先從k個點裏選一個點出發(root),則離root最遠的點,而且字典序更小的點作爲出發點不會是路更長,而如果一定有些點一定要經過父節點則意味着要回到父節點就要每條邊經過兩次,當然由於我們不需要回到父節點,所以我們減去離根節點最遠的點的距離就是最短了,當然最後還要找最小的根節點
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
const int N=200000;
vector <int>G[N];
int cities[N];
bool mk[N];
int dep[N];
int num[N];
void dfs(int u,int v)
{
if(mk[u]) num[u]=1;
else num[u]=0;
for(int i=0;i<G[u].size();i++){
int vv=G[u][i];
if(vv==v) continue;
dep[vv]=dep[u]+1;
dfs(vv,u);
num[u]+=num[vv];
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
int x,y;
for(int i=0;i<n-1;i++){
scanf("%d%d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
int st;
for(int i=0;i<m;i++){
scanf("%d",&x);
cities[i]=x;
st=x;
mk[x]=1;
}
dfs(st,0);
// for(int i=0;i<m;i++)
// printf("%d %d\n",cities[i],dep[cities[i]]);
int len=0;
for(int i=0;i<m;i++){
x=cities[i];
if(dep[x]>dep[st]){
st=x;
}
if(dep[x]==dep[st] && st>x){
st=x;
}
}
memset(dep,0,sizeof dep);
dfs(st,0);
len=0;
int res=0;
for(int i=1;i<=n;i++){
x=i;
//printf("%d\n",num[x]);
if(num[x]>0 && m-num[x]>0){ res+=2;}
if(mk[x]&&dep[x]>len) len=dep[x];
}
for(int i=0;i<m;i++){
x=cities[i];
if(dep[x]==len && x<st) st=x;
}
printf("%d\n",st);
printf("%d\n",res-len);
}
/*
6 3
1 2
1 4
1 3
2 5
2 6
6 4 3
*/