【启发式搜索】Codechef March Cook-Off 2018. Maximum Tree Path
有点像计蒜之道里的 京东的物流路径
题目描述
给定一棵 N 个节点的树,每个节点有一个正整数权值。记节点 i 的权值为 Ai。
考虑节点 u 和 v 之间的一条简单路径,记 dist(u, v) 为其长度,gcd(u, v) 为路径上所有节点
(包含 u 和 v)的权值的最大公因子。min(u, v) 为路径上所有节点的权值的最小值。
请求出所有节点对 (u, v) 中 dist(u, v) · gcd(u, v) · min(u, v) 的最大值
输入格式
输入的第一行包含一个整数 T,代表测试数据的组数。接下来是 T 组数据。
每组数据的第一行包含一个整数 N,代表树中节点的个数。接下来一行包含 N 个整数
A1, A2, . . . , AN。
接下来 N − 1 行,每行包含三个整数 u, v, w,代表节点 u 和 v 之间连有一条长度为 w 的边。
输出格式
对于每组数据,输出一行,包含一个整数,代表所求答案
数据范围
• 1 ≤ T ≤ 100
• 2 ≤ N ≤ 10^5
• 2 ≤ ∑N ≤ 10^5
• 1 ≤ Ai ≤ 10^4
• 1 ≤ u, v ≤ N
• 1 ≤ w ≤ 10^5
题目分析
常规做法
和京东的物流路径不同的是,需要在外层枚举路径的gcd,并把两端点是gcd倍数的边存下,按照端点权值的较小值排序。之后就相当于是用这些边来和那题一样做了。
参见:[树的直径] Codechef March Cook-Off 2018. Maximum Tree Path
启发式搜索
我也不知道复杂度是多少
每一次搜索时若$dia*mn*gcd(dia为直径)<ans$就return。
1 #include<bits/stdc++.h> 2 typedef long long ll; 3 const int maxn = 100035; 4 5 struct Edge 6 { 7 int y,val; 8 Edge(int a=0, int b=0):y(a),val(b) {} 9 }edges[maxn<<1]; 10 long long ans; 11 int tt,n,dia,S,T,a[maxn],dis[maxn]; 12 int edgeTot,head[maxn],nxt[maxn<<1]; 13 14 int read() 15 { 16 char ch = getchar(); 17 int num = 0; 18 bool fl = 0; 19 for (; !isdigit(ch); ch=getchar()) 20 if (ch=='-') fl = 1; 21 for (; isdigit(ch); ch=getchar()) 22 num = (num<<1)+(num<<3)+ch-48; 23 if (fl) num = -num; 24 return num; 25 } 26 int gcd(int a, int b){return !b?a:gcd(b, a%b);} 27 void addedge(int u, int v) 28 { 29 int c = read(); 30 edges[++edgeTot] = Edge(v, c), nxt[edgeTot] = head[u], head[u] = edgeTot; 31 edges[++edgeTot] = Edge(u, c), nxt[edgeTot] = head[v], head[v] = edgeTot; 32 } 33 void dfs(int x, int fa, int c) 34 { 35 dis[x] = c; 36 for (int i=head[x]; i!=-1; i=nxt[i]) 37 if (edges[i].y!=fa) dfs(edges[i].y, x, c+edges[i].val); 38 } 39 void fnd(int x, int fa, ll d, int g, int mn) 40 { 41 if (1ll*dia*g*mn <= ans) return; 42 if (ans < 1ll*d*g*mn) ans = 1ll*d*g*mn; 43 for (int i=head[x]; i!=-1; i=nxt[i]) 44 if (edges[i].y!=fa) 45 fnd(edges[i].y, x, d+1ll*edges[i].val, gcd(g, a[edges[i].y]), std::min(mn, a[edges[i].y])); 46 } 47 void fndDiameter() 48 { 49 S = T = 0, dis[0] = -0x3f3f3f3f; 50 dfs(1, 1, 0); 51 for (int i=1; i<=n; i++) 52 if (dis[S] < dis[i]) S = i; 53 dfs(S, S, 0); 54 for (int i=1; i<=n; i++) 55 if (dis[T] < dis[i]) 56 T = i, dia = dis[T]; 57 fnd(S, S, 0, a[S], a[S]); 58 } 59 int main() 60 { 61 tt = read(); 62 while (tt--) 63 { 64 n = read(), ans = dia = edgeTot = 0; 65 memset(head, -1, (n+2)<<2); 66 for (int i=1; i<=n; i++) a[i] = read(); 67 for (int i=1; i<n; i++) addedge(read(), read()); 68 fndDiameter(); 69 for (int i=1; i<=n; i++) 70 fnd(i, i, 0, a[i], a[i]); 71 printf("%lld ",ans); 72 } 73 return 0; 74 }
END