CodeForces - 592D Super M 題解
阿新 • • 發佈:2017-07-16
fin read size void spa clu family () 思路
題目大意:
一棵樹 n個點 有m個點被標記 求經過所有被標記的點的最短路徑的長度以及起點(如有多條輸出編號最小的起點)。
思路:
1.當且僅當一個點本身或其子樹中有點被標記時該點在最短的路徑上因此,可以將多余的點刪去,得到新的一棵樹。
2.不難發現,新樹上的邊必定被經過一次或兩次,而且當只經過一次的邊的集合為樹的直徑時,路徑最短。
反思:
“如有多條輸出編號最小的起點”是個坑點,要在最遠的點中找出編號最小的當端點。
代碼:
1 #include<cstdio> 2 #define u v[i] 3 const int M=250000; 4 int s,a[M],v[M],hea[M],nex[M];5 bool b[M]; 6 7 int read() 8 { 9 int x=0; char ch=getchar(); 10 while (ch<48 || ch>57) ch=getchar(); 11 while (ch>47 && ch<58) x=(x<<1)+(x<<3)+ch-48,ch=getchar(); 12 return x; 13 } 14 15 void add(int x,int y) { v[++s]=y,nex[s]=hea[x],hea[x]=s; }16 17 void dfs(int x,int p) 18 { 19 for (int i=hea[x];i;i=nex[i]) 20 if (u^p) dfs(u,x),b[x]|=b[u]; 21 } 22 23 void DFS(int x,int y,int p) 24 { 25 a[x]=y; 26 for (int i=hea[x];i;i=nex[i]) 27 if (b[u] && u^p) DFS(u,y+1,x); 28 } 29 30 int main() 31 { 32 int n=read(),m=read(),i,x,y;33 for (i=1;i<n;++i) x=read(),y=read(),add(x,y),add(y,x); 34 for (i=b[y=read()]=1;i<m;++i) b[read()]=1; 35 for (dfs(y,0),a[0]=s=-1,i=1;i<=n;++i) s=s+b[i]; 36 for (DFS(y,x=0,0),i=1;i<=n;++i) 37 if (b[i] && a[x]<a[i]) x=i; 38 for (DFS(x,y=0,0),i=1;i<=n;++i) 39 if (b[i] && a[y]<a[i]) y=i; 40 printf("%d\n%d\n",x<y?x:y,s+s-a[y]); 41 return 0; 42 }
CodeForces - 592D Super M 題解