• SPOJ6717 Two Paths 树形dp



    首先有朴素的(O(n^2))想法

    首先枚举断边,之后对于断边之后的两棵子树求出直径

    考虑优化这个朴素的想法

    考虑换根(dp)

    具体而言,首先求出(f[i], fs[i])表示(i)号点向下的最长链以及(i)号子树内部最长的直径

    并且在求出(g[i])表示(fa[i])(i)号节点子树外的最长链

    (gs[i])表示(i)号节点子树外的直径

    对于所有的(fs[i] * gs[i])(max)即为答案


    首先一遍(dfs)(f, fs)求出来

    考虑怎么求(gs[o]),有以下几种可能

    • 一条(fa[o])引申出去的链 + (fa[o]) 除了(o)子树以外的最长链

    • (gs[fa])

    • 两条(fa[o])除了(o)子树以外的链的和

    用前缀和后缀来做到删除


    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    
    #define ll long long
    #define ri register int
    #define rep(io, st, ed) for(ri io = st; io <= ed; io ++)
    #define drep(io, ed, st) for(ri io = ed; io >= st; io --)
    
    #define tpr template <typename ra>
    tpr inline void cmin(ra &a, ra b) { if(a > b) a = b; }
    tpr inline void cmax(ra &a, ra b) { if(a < b) a = b; }
        
    #define gc getchar
    inline int read() {
        int p = 0, w = 1; char c = gc();
        while(c > '9' || c < '0') { if(c == '-') w = -1; c = gc(); }
        while(c >= '0' && c <= '9') p = p * 10 + c - '0', c = gc();
        return p * w;
    }
        
    const int sid = 200050;
        
    ll ans;
    int n, cnp;
    int cap[sid], nxt[sid], node[sid];
        
    inline void addedge(int u, int v) {
        nxt[++ cnp] = cap[u]; cap[u] = cnp; node[cnp] = v;
    }
        
    int f[sid], fs[sid];
    int g[sid], gs[sid], q[sid], ps[sid], ss[sid];
        
    #define cur node[i]
    void dfs1(int o, int fa) {
        for(int i = cap[o]; i; i = nxt[i])
        if(cur != fa) {
            dfs1(cur, o);
            cmax(fs[o], fs[cur]);
            cmax(fs[o], f[cur] + f[o] + 1);
            cmax(f[o], f[cur] + 1);
        }
    }
    
    void dfs2(int o, int fa) {
        
        if(!fa) g[o] = -1;
        
        int tot = 0;
        int sx = 0, mx = 0, px = 0;
        
        for(int i = cap[o]; i; i = nxt[i])
            if(cur != fa) q[++ tot] = cur;
        
        rep(i, 1, tot + 1) ps[i] = ss[i] = 0;
        
        rep(i, 1, tot) {
            int p = q[i];
            cmax(g[p], g[o] + 1);
            cmax(g[p], ps[i - 1]);
            ps[i] = max(ps[i - 1], f[p] + 1);
        }
        
        drep(i, tot, 1) {
            int p = q[i];
            cmax(g[p], ss[i +  1]);
            ss[i] = max(ss[i + 1], f[p] + 1);
        }
        
        rep(i, 1, tot) {
            int p = q[i];
            cmax(gs[p], ps[i - 1] + ss[i + 1]);
            cmax(gs[p], gs[o]);
            cmax(gs[p], g[o] + 1 + ps[i - 1]);
            cmax(gs[p], g[o] + 1 + ss[i + 1]);
        }
        
        rep(i, 1, tot) {
            int p = q[i];
            cmax(gs[p], mx + sx);
            cmax(gs[p], px); cmax(px, fs[p]);
            if(f[p] + 1 >= mx) sx = mx, mx = f[p] + 1;
            else if(f[p] + 1 >= sx) sx = f[p] + 1;
        }
        
        mx = sx = px = 0;
        
        drep(i, tot, 1) {
            int p = q[i];
            cmax(gs[p], mx + sx);
            cmax(gs[p], px); cmax(px, fs[p]);
            if(f[p] + 1 >= mx) sx = mx, mx = f[p] + 1;
            else if(f[p] + 1 >= sx) sx = f[p] + 1;
        }
        
        for(int i = cap[o]; i; i = nxt[i])
            if(cur != fa) {
                cmax(ans, 1ll * fs[cur] * gs[cur]);
                dfs2(cur, o);
            }
    }
    
    int main() {
        n = read();
        rep(i, 2, n) {
            int u = read(), v =read();
            addedge(u, v); addedge(v, u);
        }
        dfs1(1, 0); dfs2(1, 0);
        printf("%lld
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    Redis-命令-脚本
    Redis-命令-事务
    Redis-命令-发布订阅
    Redis-命令-HyperLogLog
    Redis-命令-有序集合(sorted set)
    Redis-命令-集合(Set)
    Redis-命令-列表(List)
    Python实例浅谈之三Python与C/C++相互调用
    python调用(运行)外部程序
    Sublime Text3 配置设置攻略
  • 原文地址:https://www.cnblogs.com/reverymoon/p/10029291.html
Copyright © 2020-2023  润新知