在線評測:
http://codevs.cn/problem/3728/
整體思路:
首先我們認真閱讀題意,發現這是一個樹,這樣子我們就可以加特技了!
我們在搜索一個點的時候,我們先把這個點所能連出的所有點的和加起來並記錄,並記錄這個點連出的最大值和次大值。同時我們去用他和他父節點記錄的以上數值進行運算,將他父節點的記錄的和減去這個點的權值,然後將權值與父節點的和相乘加入到結果中,並用父節點連出的最大值,或次大值(最大值爲這個點本身)來更新全局最大值。在1號點時我們特判一下什麼都不做就行。同時我們這樣運算對於兩個點,我們只計算了他倆聯合一次,所以結果最後要乘2輸出,
失誤之處:
開始運算結果中間量的時候沒有開long long 於是很悲催的炸了幾個點,
體會心得:
注意數值範圍!!!
AC代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
#include <cstdio> #include <cmath> #include <cstring> #include <algorithm> using namespace std; int n,w[300000],u,v,sum,maxn; int head[600000],nxt[600000],to[600000]; int jlm[300000],jls[300000],jlh[300000],fa[300000]; int jlwm[300000],f1; bool vis[300000]; long long ans = 0; void cr( int x, int y) { sum++; nxt[sum] = head[x]; head[x] = sum; to[sum] = y; } void dfs( int x) { vis[x] = true ; if (fa[x] == 1 && f1 == 1) { } else if (fa[x]) { jlh[fa[x]] -= w[x]; long long ftp = w[x],itp = jlh[fa[x]]; ans += ftp * itp; ans %= 10007; if (x != jlwm[fa[x]]) { maxn = max(maxn,w[x] * jlm[fa[x]]); } else { maxn = max(maxn,w[x] * jls[fa[x]]); } } for ( int tp = head[x];tp;tp = nxt[tp]) { if (x == 1) f1++; if (jlm[x] < w[to[tp]]) { jlm[x] = w[to[tp]]; jlwm[x] = to[tp]; } jlh[x] += w[to[tp]]; } for ( int tp = head[x];tp;tp = nxt[tp]) { if (jls[x] < w[to[tp]] && to[tp] != jlwm[x]) { jls[x] = w[to[tp]]; } } for ( int tp = head[x];tp && !vis[to[tp]];tp = nxt[tp]) { fa[to[tp]] = x; dfs(to[tp]); } } int main() { scanf ( "%d" ,&n); for ( int i = 1;i <= n - 1;i++) { scanf ( "%d%d" ,&u,&v); cr(u,v); cr(v,u); } for ( int i = 1;i <= n;i++) scanf ( "%d" ,&w[i]); dfs(1); printf ( "%d %lld\n" ,maxn,ans * 2 % 10007); return 0; } |