【noip2007】树网的核
题解:
首先我们要知道一个性质:如果有多条直径 这个核不论在哪条直径上 答案都是一样的
这样我们就可以随便找一条直径 在这条直径上枚举核的位置
并且dfs预处理maxlon[i] (i在直径上) 表示到i的路径不经过直径的 离i最远的点到i的距离
这时核的偏心距就是max(maxlon[i],核的端点到直径的端点的长度) (i为核上的点)
这样就能O(n)求解
代码:
1 #include <cstdio> 2 const int N=301,M=1001; 3 struct inli{ 4 int next,data,lon; 5 inli(const int a=0,const int b=0,const int c=0): 6 next(a),data(b),lon(c){} 7 }line[N*2]; 8 int S,n,m,son[N],fat[N],dis[N],bo[N],maxlon[N],seclon[N],hard[N],nl; 9 int max(int x,int y){ return x>y ? x : y;} 10 int min(int x,int y){ return x<y ? x : y;} 11 void makedis(int t){ 12 bo[t]=1; 13 for (int i=son[t];i;i=line[i].next) 14 if (!bo[line[i].data]){ 15 int ne=line[i].data; 16 dis[ne]=dis[t]+line[i].lon; 17 makedis(ne); 18 } 19 } 20 void makefat(int t){ 21 for (int i=son[t];i;i=line[i].next) 22 if (line[i].data!=fat[t]){ 23 int ne=line[i].data; 24 fat[ne]=t; 25 makefat(ne); 26 if (maxlon[ne]+line[i].lon>maxlon[t]){ 27 seclon[t]=maxlon[t]; 28 maxlon[t]=maxlon[ne]+line[i].lon; 29 hard[t]=i; 30 } 31 } 32 } 33 int makef(int x,int y){ 34 if (!x) return 0; 35 int i=hard[x]; 36 if (y<line[i].lon) return maxlon[x]; 37 return max(seclon[x],makef(line[i].data,y-line[i].lon)); 38 } 39 int getans(){ 40 int res=100000000; 41 for (int i=S,x=seclon[S];i;x+=line[hard[i]].lon,i=line[hard[i]].data){ 42 if (x>res) break; 43 res=min(res,max(makef(i,m),x)); 44 } 45 return res; 46 } 47 int main(){ 48 scanf("%d%d",&n,&m); 49 for (int x,y,z,i=1;i<n;i++){ 50 scanf("%d%d%d",&x,&y,&z); 51 line[++nl]=inli(son[x],y,z),son[x]=nl; 52 line[++nl]=inli(son[y],x,z),son[y]=nl; 53 } 54 makedis(1); 55 int x=0; 56 for (int i=1;i<=n;i++) 57 if (dis[i]>x) x=dis[i],S=i; 58 makefat(S); 59 printf("%d",getans()); 60 }