• 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
    ", ans[i]);
    }
    int main(){
        init();
        return 0;
    }
    View Code
  • 相关阅读:
    LINQ学习(1)
    [转]键盘上的标点符号的中英文名称对照表
    微信Android ANR原理解析及解决方案
    IOS错误日志抓取和分析
    蚂蚁金服测开面试题--转账功能
    MySQL CONV()函数
    分页功能
    在alert里面加入一个页面,子页面传值父页面
    com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; che
    缘起 网络编程
  • 原文地址:https://www.cnblogs.com/smilke/p/11615491.html
Copyright © 2020-2023  润新知