洛谷 P1099 树网的核(树的直径+贪心)

题目链接:https://www.luogu.com.cn/problem/P1099

 

用两边DFS求出直径,用f记录fa,这样就记录下了直径的路径,将直径上的点vis标记为1。然后枚举左右端点(或者尺取法,但不会)。

贪心考虑对答案的贡献:

假设直径的两个端点为a和b,当前左右端点为i,j,

对答案的贡献只有a,i之间的距离、b,j之间的距离、i,j中每个节点的子树的最远距离。

那么可以对于直径上的每一个节点做一次关于它的子树(除直径)的DFS,找出子树最远距离,存在dt[]中。注意不要每更换一次左右端点就重新求一遍,因为vis
会影响(坑)。

 

AC代码:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<queue>
 5 using namespace std;
 6 int n,s;
 7 const int N=400;
 8 int tot,ans=0x7f7f7f7f,anss,ansss;
 9 int head[N];
10 int f[N],maxd,dis[N],diss[N],dt[N];
11 int p,vis[N];
12 struct node{
13     int to,next,w;
14 }edge[N<<1];
15 void add(int u,int v,int w){
16     edge[tot].to=v;
17     edge[tot].next=head[u];
18     edge[tot].w=w;
19     head[u]=tot++;
20 }
21 void DFS(int u,int fa){
22     f[u]=fa;
23     if(maxd<dis[u]){
24         maxd=dis[u];
25         p=u;
26     }
27     for(int i=head[u];i!=-1;i=edge[i].next){
28         int v=edge[i].to;
29         if(vis[v]||v==fa) continue;
30         vis[v]=1;
31         dis[v]=dis[u]+edge[i].w;
32         DFS(v,u);
33     }
34 }
35 void DFSD(int u){
36     if(diss[u]>maxd) maxd=diss[u];
37     for(int i=head[u];i!=-1;i=edge[i].next){
38         int v=edge[i].to;
39         if(vis[v]) continue;
40         vis[v]=1;
41         diss[v]=diss[u]+edge[i].w;
42         DFSD(v);
43     }
44 }
45 int main(){
46     memset(head,-1,sizeof(head));
47     memset(f,-1,sizeof(f));
48     scanf("%d%d",&n,&s);
49     for(int i=1;i<n;i++){
50         int u,v,w;
51         scanf("%d%d%d",&u,&v,&w);
52         add(u,v,w); add(v,u,w); 
53     }
54     DFS(1,-1);
55     memset(dis,0,sizeof(dis));
56     memset(f,-1,sizeof(f));
57     memset(vis,0,sizeof(vis));
58     int a=p;
59     maxd=0;
60     DFS(p,-1);
61     int b=p;
62     memset(vis,0,sizeof(vis));
63     for(int i=b;i!=-1;i=f[i]) vis[i]=1;
64     for(int i=b;i!=-1;i=f[i]){
65         for(int j=i;j!=-1&&dis[i]-dis[j]<=s;j=f[j]){
66             anss=max(dis[b]-dis[i],dis[j]);
67             for(int k=i;k!=f[j];k=f[k]){
68                 maxd=0;
69                 if(dt[k]) maxd=dt[k];
70                 else { DFSD(k); dt[k]=maxd;}
71                 anss=max(anss,maxd);
72             }
73             ans=min(ans,anss);
74         }
75     }
76     printf("%d",ans);
77     return 0;
78 }
AC代码

 

posted @ 2020-09-19 22:58  dfydn  阅读(162)  评论(0)    收藏  举报