NOIP2014 聯合權值 解題報告(亂搞(據說這道題是樹狀dp,感覺好像是))

在線評測:

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;
}

發佈了65 篇原創文章 · 獲贊 14 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章