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 }
请各位大佬斧正(反正我不认识斧正是什么意思)