zoukankan      html  css  js  c++  java
  • [长链剖分优化dp] BZOJ 3522/4543 Hotel

    题目大意

    给定一棵 (n(nleq 5000)) 个点的树,求选出三个不同的点,使得三个点两两之间间距相等的方案数。

    题解

    (f[u][j]) 表示以 (u) 为根的子树中,到 (u) 距离为 (j) 的结点的数目,设 (g[v][j]) 表示lca在以 (v) 为根的子树中 ,且到 (v) 的距离相同,且 (v)(u) 的距离加 (j) 等于它们到 (v) 的距离的结点对数。

    每访问到 (u) 的一个儿子 (v),就有

    [ans+=f[u][j] imes g[v][j+1]+f[v][j-1] imes g[u][j]\ g[u][j+1]+=f[u][j+1] imes f[v][j]\ g[u][j-1]+=g[v][j]\ f[u][j]+=f[v][j-1] ]

    时间复杂度 (O(n^2))

    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    #define RG register int
    #define LL long long
    
    template<typename elemType>
    inline void Read(elemType& T) {
        elemType X = 0, w = 0; char ch = 0;
        while (!isdigit(ch)) { w |= ch == '-';ch = getchar(); }
        while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
        T = (w ? -X : X);
    }
    
    struct Graph {
        struct edge { int Next, to; };
        edge G[10010];
        int head[5010];
        int cnt;
    
        Graph() :cnt(2) {}
        void clear(int n) {
            cnt = 2;fill(head, head + n + 2, 0);
        }
        void add_edge(int u, int v) {
            G[cnt].to = v;
            G[cnt].Next = head[u];
            head[u] = cnt++;
        }
    };
    Graph G;
    int N;
    
    int Height[5005];
    LL f[5005][5005], g[5005][5005], ans;
    
    void DFS(int u, int fa) {
        Height[u] = 0;
        f[u][0] = 1;
        for (int i = G.head[u];i;i = G.G[i].Next) {
            int v = G.G[i].to;
            if (v == fa) continue;
            DFS(v, u);
            Height[u] = max(Height[u], Height[v] + 1);
            for (int j = 0;j <= Height[u];++j)
                ans += f[u][j] * g[v][j + 1] + g[u][j] * f[v][j - 1];
            for (int j = 0;j <= Height[u];++j) {
                g[u][j + 1] += f[u][j + 1] * f[v][j];
                if (j >= 1) {
                    g[u][j - 1] += g[v][j];
                    f[u][j] += f[v][j - 1];
                }
            }
        }
    }
    
    int main() {
        Read(N);
        for (int i = 1;i <= N - 1;++i) {
            int u, v;
            Read(u);Read(v);
            G.add_edge(u, v);
            G.add_edge(v, u);
        }
        DFS(1, 0);
        printf("%lld
    ", ans);
    
        return 0;
    }
    

    长链剖分优化dp

    BZOJ 4543这道题 (n) 扩大到了 (10^5)

    #include <bits/stdc++.h>
    using namespace std;
    
    #define RG register int
    #define LL long long
    
    template<typename elemType>
    inline void Read(elemType& T) {
        elemType X = 0, w = 0; char ch = 0;
        while (!isdigit(ch)) { w |= ch == '-';ch = getchar(); }
        while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
        T = (w ? -X : X);
    }
    
    const int maxn = 100005;
    
    struct Graph {
        struct edge { int Next, to; };
        edge G[maxn << 1];
        int head[maxn];
        int cnt;
    
        Graph() :cnt(2) {}
        void clear(int n) {
            cnt = 2;fill(head, head + n + 2, 0);
        }
        void add_edge(int u, int v) {
            G[cnt].to = v;
            G[cnt].Next = head[u];
            head[u] = cnt++;
        }
    };
    Graph G;
    int N;
    
    int Height[maxn], Hson[maxn];
    LL temp[maxn * 5], * f[maxn], * g[maxn], * id = temp, ans;
    
    void DFS_Init(int u, int fa) {
        Height[u] = 1;
        for (int i = G.head[u];i;i = G.G[i].Next) {
            int v = G.G[i].to;
            if (v == fa) continue;
            DFS_Init(v, u);
            Height[u] = max(Height[u], Height[v] + 1);
            if (Height[v] > Height[Hson[u]]) Hson[u] = v;
        }
        return;
    }
    
    void DFS(int u, int fa) {
        if (Hson[u]) {
            f[Hson[u]] = f[u] + 1;
            g[Hson[u]] = g[u] - 1;
            DFS(Hson[u], u);
        }
        f[u][0] = 1;ans += g[u][0];
        for (int i = G.head[u];i;i = G.G[i].Next) {
            int v = G.G[i].to;
            if (v == fa || v == Hson[u]) continue;
            f[v] = id;id += Height[v] << 1;
            g[v] = id;id += Height[v] << 1;
            DFS(v, u);
            for (int j = 0;j < Height[v];++j) {
                if (j) ans += g[v][j] * f[u][j - 1];
                ans += g[u][j + 1] * f[v][j];
            }
            for (int j = 0;j < Height[v];++j) {
                g[u][j + 1] += f[u][j + 1] * f[v][j];
                if (j) g[u][j - 1] += g[v][j];
                f[u][j + 1] += f[v][j];
            }
        }
    }
    
    int main() {
        Read(N);
        for (int i = 1;i <= N - 1;++i) {
            int u, v;
            Read(u);Read(v);
            G.add_edge(u, v);
            G.add_edge(v, u);
        }
        DFS_Init(1, 0);
        f[1] = id;id += Height[1] << 1;
        g[1] = id;id += Height[1] << 1;
        DFS(1, 0);
        printf("%lld
    ", ans);
    
        return 0;
    }
    
  • 相关阅读:
    Gitkraken使用教程
    request.getHeader中区分大小写参数
    MySql 中查询列表中添加序号
    解决windows 下mysql 表名自动转成小写的问题
    MYSQL服务无法启动,服务没有任何错误;解决方法
    idea中设置一键生成方法注释和类注释
    Windows10下安装MySQL8.0.21-64
    navicat连接mysql出现2059错误的解决方法
    解决tomca在eclipse中正常启动,在bin下启动闪退问题
    QT线程的结束
  • 原文地址:https://www.cnblogs.com/AEMShana/p/14598744.html
Copyright © 2011-2022 走看看