P1099 树网的核——模拟+树形结构
P1099 树网的核
无根树,在直径上找到一条长度不超过s的路径,使得最远的点距离这条路径的距离最短;
首先两遍dfs找到直径(第二次找的时候一定要吧father[]清零)
在找到的直径下枚举长度不超过s的链,ans的下界是直径两端点到这条链距离的最小值;
然后将直径上的点都标记,再次求一下别的点到直径的距离。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int maxn=620; 6 int n,s; 7 int pre[maxn],last[maxn],other[maxn],len[maxn],l; 8 9 void add(int x,int y,int z) 10 { 11 l++; 12 pre[l]=last[x]; 13 last[x]=l; 14 other[l]=y; 15 len[l]=z; 16 } 17 18 int dis[maxn],father[maxn],vis[maxn]; 19 int l1,l2; 20 21 void dfs(int x) 22 { 23 for(int p=last[x];p;p=pre[p]) 24 { 25 int v=other[p]; 26 if(v==father[x]||vis[v]) continue; 27 father[v]=x; 28 dis[v]=dis[x]+len[p]; 29 dfs(v); 30 } 31 } 32 33 34 int main() 35 { 36 scanf("%d%d",&n,&s); 37 for(int i=1;i<n;i++) 38 { 39 int x,y,z; 40 scanf("%d%d%d",&x,&y,&z); 41 add(x,y,z); 42 add(y,x,z); 43 } 44 45 dis[1]=0; dfs(1); 46 l1=1; 47 for(int i=1;i<=n;i++) if(dis[i]>dis[l1]) l1=i; 48 memset(father,0,sizeof(father)); 49 dis[l1]=0; dfs(l1); l2=1; 50 for(int i=1;i<=n;i++) if(dis[i]>dis[l2]) l2=i; 51 52 //printf("??%d %d\n",l1,l2); 53 54 int ans=2147483647,j=l2; 55 for(int i=l2;i;i=father[i]) 56 { 57 while(father[j]&&dis[i]-dis[father[j]]<=s) j=father[j]; 58 ans=min(ans,max(dis[l2]-dis[i],dis[j])); 59 } 60 for(int i=l2;i;i=father[i]) vis[i]=1; 61 for(int i=l2;i;i=father[i]) 62 { 63 dis[i]=0; 64 dfs(i); 65 } 66 for(int i=1;i<=n;i++) ans=max(ans,dis[i]); 67 printf("%d",ans); 68 return 0; 69 }