洛谷 P4408 [NOI2003] 逃学的小孩 题解

Analysis

题意虽然说先去谁家再去谁家,但是我们不需要管这个,因为AA、BB、CC三个点我们可以任意互相交换它们所代表的对象,所以题目要求的就是在一棵树上找到3个点AA、BB、CC令AB+BCAB+BC最大,同时要满足AC>ABAC>AB。

由于这是一棵树,它满足非常可爱的性质,就是如果找一个点出去两条路径使它们的合最大,那么一条是直径时一定会存在一种最大的方案。

所以我们可以使要找的两条路径其中一条是直径(设为ABAB),然后枚举剩下的点,找到一个到达直径端点最长的另一条路径,不过因为题目要满足一个AC>ABAC>AB,所以我们需要在每次枚举的时候(设为CC),选择ACAC和BCBC的较小的一条边作为另一条路径。可以看到,若是ACAC是小于BCBC的,则选择的路径是ACAC,实际走的路线是CACA+ABAB,满足题目要求的CA<CBCA<CB,而若是选择的是BCBC,实际路线是CBCB+BABA,也符合题意要求的CB<CACB<CA。

至此,就可以写出代码了,跑2遍dfs找出直径,再对直径起点和终点跑出对每个点的路径长度,然后计算答案。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #define int long long
  6 #define maxn 200000+10
  7 using namespace std;
  8 inline int read() 
  9 {
 10     int x=0;
 11     bool f=1;
 12     char c=getchar();
 13     for(; !isdigit(c); c=getchar()) if(c=='-') f=0;
 14     for(; isdigit(c); c=getchar()) x=(x<<3)+(x<<1)+c-'0';
 15     if(f) return x;
 16     return 0-x;
 17 }
 18 inline void write(int x)
 19 {
 20     if(x<0){putchar('-');x=-x;}
 21     if(x>9)write(x/10);
 22     putchar(x%10+'0');
 23 }
 24 int n,m,cnt,com,sta,ed,ans;
 25 int dis1[maxn],dis2[maxn],head[2*maxn];
 26 struct node
 27 {
 28     int to,val,nxt;
 29 }edge[2*maxn];
 30 inline void add(int x,int y,int z)
 31 {
 32     cnt++;
 33     edge[cnt].to=y;
 34     edge[cnt].val=z;
 35     edge[cnt].nxt=head[x];
 36     head[x]=cnt++;
 37 }
 38 inline void dfs1_tree_d(int x,int fa)
 39 {
 40     for(int i=head[x];i;i=edge[i].nxt)
 41     {
 42         int to=edge[i].to;
 43         if(to==fa) continue;
 44         dis1[to]=dis1[x]+edge[i].val;
 45         if(dis1[to]>com) 
 46         {
 47             com=dis1[to];
 48             sta=to;
 49         }
 50         dfs1_tree_d(to,x);
 51     }
 52 }
 53 inline void dfs2_tree_d(int x,int fa)
 54 {
 55     for(int i=head[x];i;i=edge[i].nxt)
 56     {
 57         int to=edge[i].to;
 58         if(to==fa) continue;
 59         dis2[to]=dis2[x]+edge[i].val;
 60         if(dis2[to]>com) 
 61         {
 62             com=dis2[to];
 63             ed=to;
 64         }
 65         dfs2_tree_d(to,x);
 66     }
 67 }
 68 inline void find1_long(int x,int fa)
 69 {
 70     for(int i=head[x];i;i=edge[i].nxt)
 71     {
 72         int to=edge[i].to;
 73         if(to==fa) continue;
 74         dis1[to]=dis1[x]+edge[i].val;
 75         find1_long(to,x);
 76     }
 77 }
 78 inline void find2_long(int x,int fa)
 79 {
 80     for(int i=head[x];i;i=edge[i].nxt)
 81     {
 82         int to=edge[i].to;
 83         if(to==fa) continue;
 84         dis2[to]=dis2[x]+edge[i].val;
 85         find2_long(to,x);
 86     }
 87 }
 88 signed main()
 89 {
 90 //    freopen("truant.in","r",stdin);
 91 //    freopen("truant.out","w",stdout);
 92     n=read();m=read();
 93     for(int i=1;i<=m;i++)
 94     {
 95         int x=read(),y=read(),z=read();
 96         add(x,y,z);
 97         add(y,x,z);
 98     }
 99     com=0;
100     dfs1_tree_d(1,0);
101     com=0;
102     dfs2_tree_d(sta,0);
103     ans=dis2[ed];
104     memset(dis1,0,sizeof(dis1));
105     memset(dis2,0,sizeof(dis2));
106     find1_long(sta,0);
107     find2_long(ed,0);
108     com=0;
109     for(int i=1;i<=n;i++)
110     {
111         int len=min(dis1[i],dis2[i]);
112         if(len>com) com=len;
113     }
114     ans+=com;
115     write(ans);
116     return 0;
117 }

请各位大佬斧正(反正我不认识斧正是什么意思)

猜你喜欢

转载自www.cnblogs.com/handsome-zyc/p/11628164.html