Bzoj 1131[POI2008]STA-Station (树形DP)

Bzoj 1131[POI2008]STA-Station (树形DP)

状态:
\(f[i]\)为以\(i\)为根的深度之和,然后考虑从他父亲转移.
发现儿子的深度及其自己的深度\(-1\)
其余的\(+1\),记录一下\(size\)就ok了
转移:
\(f[i] = f[fa] + n - 2 * size[i]\)
记忆化搜索即可.
Bzoj 可能过不了,原因貌似是栈空间不足,可以去洛谷提交,我这里的解决方法是.记忆化搜索的时候用\(n\)作为开头.然后就过了.

#include <iostream>
#include <cstdio>
#define ll long long
const int maxN = 1000000 + 7;

ll f[maxN],n; // f[i] = f[fa] + n - 2 * size[i];
int size[maxN],dep[maxN],fa[maxN];

struct Node {
    int v,nex;
}Map[maxN << 1];
int head[maxN],num;

inline int read() {
    int x = 0,f = 1;char c = getchar();
    while(c < '0' || c > '9') {if(c == '-')f = -1;c = getchar();}
    while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
    return x * f;
}

inline ll max(ll a,ll b) {return a > b ? a : b;}

void add_Node(int u,int v) {
    Map[++ num] = (Node) {v,head[u]};
    head[u] = num;
    return ; 
}

void work_fst(int now) {
    size[now] = 1;dep[now] = dep[fa[now]] + 1;
    for(int i = head[now];i;i = Map[i].nex) {
        int v = Map[i].v;
        if(v != fa[now]) {
            fa[v] = now;
            work_fst(v);
            size[now] += size[v];
        }
    }
    return ;
}

void work_dp(int now) {
    for(int i = head[now];i;i = Map[i].nex) {
        int v = Map[i].v;
        if(v != fa[now]) {
            f[v] = f[now] + n - 2 * size[v];
            work_dp(v);
        }
    }
}

int main() {
    n = read();
    for(int i = 1,u,v;i < n;++ i) {
        u = read();v = read();
        add_Node(u,v);
        add_Node(v,u);
    }
    dep[0] = -1;
    work_fst(n);
    for(int i = 1;i <= n;++ i)
        f[n] += dep[i];
    work_dp(n);
    ll ans = 0;
    for(int i = 1;i <= n;++ i)
        ans = max(ans,f[i]);
    for(int i = 1;i <= n;++ i)
        if(f[i] == ans) {printf("%d\n", i);break;}
    return 0;
}
posted @ 2018-10-09 10:23  Rlif  阅读(109)  评论(0编辑  收藏  举报