Luogu P1351 联合权值 前缀和

求树上距离为二的点对权积之最值、和。

70pts:枚举每个点,bfs两层求和求最值和和。

100pts:枚举每个点,先统计所有可达节点的权值和,再枚举可达点求权值和

第二种做法较第一种的优化:

a1*a2+a1*a3+a1*a4+..a2*a1+a2*a3+...

=>a1*(sum-a1)+a2*(sum-a2)+...

好巧妙啊

要注意的一点:小心过程量爆int!

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<queue>
 6 using namespace std;
 7 
 8 int read(){
 9     int a = 0;char l = ' ',c = getchar();
10     while(c < '0'||c > '9')l = c,c = getchar();
11     while('0' <= c&&c <= '9')a = a*10+c-'0',c = getchar();
12     if(l == '-')return -a;return a;
13 }
14 
15 const int Maxn = 2e6+10;
16 
17 struct Edge{
18     int to,ne;
19 }edges[Maxn<<1];
20 
21 int first[Maxn];
22 int w[Maxn];
23 int n,m,ans,tot,top,cnte,x;
24 
25 void add_edge(int fr,int to){
26     edges[++cnte] = (Edge){to,first[fr]};
27     first[fr] = cnte;
28 }
29 
30 int main(){
31 //    freopen("x.in","r",stdin);
32 //    freopen("x.out","w",stdout);
33     n = read();
34     for(int i = 1;i < n;i++){
35         int u,v;
36         u = read(),v = read();
37         add_edge(u,v);
38         add_edge(v,u);
39     }
40     for(int i = 1;i <= n;i++)w[i] = read();
41     for(int i = 1;i <= n;i++){
42         long long s = 0;
43         int m1 = 0,m2 = 0;
44         for(int j = first[i];j;j = edges[j].ne){
45             int u = edges[j].to;
46             s += w[u];
47             if(w[u] > m1)m2 = m1,m1 = w[u];
48             else m2 = max(m2,w[u]);
49         }
50         ans = max(ans,m1*m2);
51         for(int j = first[i];j;j = edges[j].ne)
52             x = w[edges[j].to],tot = (tot+x*(s-x))%10007;
53     }
54     cout << ans << ' ' << tot;
55 return 0;
56 }
原文地址:https://www.cnblogs.com/Wangsheng5/p/11782734.html