HDU 2196 Computer 二次扫描与换根DP

Posted smilke

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 2196 Computer 二次扫描与换根DP相关的知识,希望对你有一定的参考价值。

题意:给定一棵树,求树上所有点到其最远点的距离。

数据范围: 1 <= N <= 100000

------------------------------------------我是分割线------------------------------------------

题解:对于每个节点u来说,其可能到达的最长距离为max其子树内的最长距离,其父节点不经过u的子树内的最长距离。于是,我们便可以在第一遍dfs中预处理节点x到其子树内的最长距离,顺带求一下次长距离,方便转移。

// f[x][0] 表示x到其子树中叶子节点的最长距离 ,f[x][1] 表示x到其子树中叶子节点的次长距离。 
void dfs1(int x, int fa)
    for(int i = head[x]; i; i = e[i].next) 
        int y = e[i].to;
        if(y == fa) continue;
        dfs1(y, x);
        if(f[y][0] + e[i].v > f[x][0]) //更新最长距离和次长距离。
            f[x][1] = f[x][0]; 
            f[x][0] = f[y][0] + e[i].v;
        
        else f[x][1] = max(f[x][1], f[y][0] + e[i].v);
    

在第二次扫描中,考虑每个点换根所改变的贡献。

分两种情况:①当前节点v不在父节点的最长路径上.②当前节点v在父节点的最长路径上.

于是状态转移方程显然:① d[y] = max(f[x][0], d[x]) + e[i].v; ② d[y] = max(f[x][1], d[x]) + e[i].v;

总时间复杂度O(N)。

void dfs2(int x, int fa)
    for(int i = head[x]; i; i = e[i].next)
        int y = e[i].to;
        if(y == fa) continue;
        if(f[x][0] == f[y][0] + e[i].v) d[y] = max(f[x][1], d[x]) + e[i].v; // y在x最长距离的路径上。 
        else d[y] = max(f[x][0], d[x]) + e[i].v; // y不在x最长距离的路径上。 
        ans[y] = max(d[y], f[y][0]);    
        dfs2(y, x);
    

于是,这道题就解决了,附上完整代码:

技术图片
#include<bits/stdc++.h>

#define ll long long
#define mp make_pair
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define per(i, a, b) for(int i = (a); i >= (b); i--)

using namespace std;

typedef pair<int, int> pii;
typedef double db;
const int N = 1e6 + 50;
int n, head[N], cnt = 0, ans[N];
int f[N][2], d[N];
struct node int to, next, v;  e[N]; 
inline int read()
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < 0 || ch > 9)  if(ch == -) f = -1; ch = getchar();
    while(ch >=0 && ch <=9)  x = (x<<3)+(x<<1)+(ch^48); ch = getchar();
    return x*f;

void add(int x, int y, int z) 
    e[++cnt].to = y; e[cnt].v = z;
    e[cnt].next = head[x]; head[x] = cnt;

// f[x][0] 表示x到其子树中叶子节点的最长距离 ,f[x][1] 表示x到其子树中叶子节点的次长距离。 
void dfs1(int x, int fa)
    for(int i = head[x]; i; i = e[i].next) 
        int y = e[i].to;
        if(y == fa) continue;
        dfs1(y, x);
        if(f[y][0] + e[i].v > f[x][0]) //状态转移 
            f[x][1] = f[x][0]; 
            f[x][0] = f[y][0] + e[i].v;
        
        else f[x][1] = max(f[x][1], f[y][0] + e[i].v);
    

void dfs2(int x, int fa)
    for(int i = head[x]; i; i = e[i].next)
        int y = e[i].to;
        if(y == fa) continue;
        if(f[x][0] == f[y][0] + e[i].v) d[y] = max(f[x][1], d[x]) + e[i].v; // y在x最长距离的路径上。 
        else d[y] = max(f[x][0], d[x]) + e[i].v; // y不在x最长距离的路径上。 
        ans[y] = max(d[y], f[y][0]);    
        dfs2(y, x);
    

void init()
    n = read();
    rep(i, 1, n-1) 
        int yy = read(), vv = read();
        add(i+1, yy, vv); add(yy, i+1, vv);
    
    dfs1(1, 0); ans[1] = f[1][0];
    dfs2(1, 0);
    rep(i, 1, n) printf("%d\n", ans[i]);

int main()
    init();
    return 0;
View Code

 

以上是关于HDU 2196 Computer 二次扫描与换根DP的主要内容,如果未能解决你的问题,请参考以下文章

51Nod1405树上距离和 二次扫描与换根法

[LuoguP1829]Crash的文明表格(二次扫描与换根+第二类斯特林数)

HDU 2196 Computer

HDU 2196 Computer 树形DP经典题

经典换根dp——hdu2196

Hdu2196 Computer