*已更新。
原题链接:https://www.luogu.org/problem/show?pid=1351
据说这道题模拟就行?
那为啥标签写着LCA和dp。。
我觉得正常向做法应该就是搜索+剪枝,搜索的时候顺带记录最大联合权值和总和就好。
看一眼题后就写了一暴力,死活A不了,无奈之下看了题解,发现题解有一个奇怪的做法:
1 #include <iostream> 2 #include <cstdio> 3 #define maxn 200005 4 #define INF 2147483647 5 #define mo 10007 6 using namespace std; 7 struct Edge{ 8 int from,to; 9 }; 10 Edge edge[maxn * 2]; 11 int head[maxn]; 12 int tot = 0; 13 int pointw[maxn]; 14 int n,maxw,sumw; 15 16 void add_edge(int from,int to){ 17 edge[++tot].from = head[from]; 18 edge[tot].to = to; 19 head[from] = tot; 20 } 21 22 int main(){ 23 scanf("%d",&n); 24 for (int i=1;i<n;i++){ 25 int u,v; 26 scanf("%d%d",&u,&v); 27 add_edge(u,v); 28 add_edge(v,u); 29 } 30 for (int i=1;i<=n;i++) 31 scanf("%d",&pointw[i]); 32 33 for (int u=1;u<=n;u++){ 34 int sum = 0; 35 int ma = 0; 36 int m = 0; 37 for (int i=head[u];i!=0;i=edge[i].from){ 38 if (pointw[edge[i].to] > ma){ 39 m = ma; 40 ma = pointw[edge[i].to]; 41 } 42 else 43 if (pointw[edge[i].to] > m) 44 m = pointw[edge[i].to]; 45 // cout << "i = " << i << endl; 46 // cout << "m = " << m << endl; 47 // cout << "ma = " << ma << endl; 48 sumw = (sumw + sum * pointw[edge[i].to]) % mo; 49 // cout << "sumw = " << sumw << endl; 50 sum = (sum + pointw[edge[i].to]) % mo; 51 // cout << "sum = " << sum << endl; 52 // cout << "---" << endl; 53 } 54 maxw = max(maxw,ma*m); 55 } 56 57 58 cout << maxw << " " << (sumw*2) % mo; 59 return 0; 60 }
其实是这样的,注意到对于任意两个距离为2的点, 它们中间必有一个中间点。而这个做法是从中间点入手,枚举所有的中间点,这样中间点的两边就是联合权值,然后分别记录最大值和总值就好。ma和m记录的其实是对于一个中间点所相连的两个点的权值。这个做法正确性显然。
还是大佬多啊。。我该弱的还是弱。。