zoukankan      html  css  js  c++  java
  • BJOI2014 大融合

    落谷Loj

    Description

    给定 (n) 个点,要求支持操作:

    1. 连接 ((x, y)) 这条边
    2. 求当前状态下经过 ((x, y)) 这条边的路径数量

    Solution

    考虑这题可以离线,先把树的结构建出来。

    考虑动态维护每个节点的子树大小 (size_i) 与当前联通快的根节点 (root_i)

    • 对于连接操作,设在我们建的结构中 (x)(y) 的父亲(否则 ( ext{swap})),链接这条边,相当于将 (x Rightarrow root_x) 这条链上的 (size)(+ size_y),即一个链加操作。然后将 (y) 联通块的 (root) 都赋值为 (root_x)
    • 对于查询操作,同样设在我们建的结构中 (x)(y) 的父亲(否则 ( ext{swap})),答案即为 (size_{y} * (size_{root_x} - size_{y}))

    对于 (root) 的维护,用并查集即可,做到 (O(Nlog_2N))

    对于 (size) 的维护,可以暴力树链剖分,也可以差分 (+) 树状数组(详情看 Loj #146. DFS 序 3,树上差分 1),我用了后者 (O(Nlog_2N))

    时间复杂度

    (O(N log_2N))

    Code

    #include <iostream>
    #include <cstdio>
    const int N = 100005;
    
    using namespace std;
    
    typedef long long LL;
    
    int n, m, rt[N], sz[N], dfn[N], dfncnt, fa[N];
    int opt[N], A[N], B[N], c[N];
    
    int head[N], numE = 0;
    
    struct E {
        int next, v;
    } e[N << 1];
    
    inline void addEdge(int u, int v) {
        e[++numE] = (E){ head[u], v };
        head[u] = numE;
    }
    
    int find(int x) { return rt[x] == x ? x : rt[x] = find(rt[x]); }
    
    void inline add(int x, int k) {
        if (x == 0)
            return;
        for (; x <= n; x += x & -x) c[x] += k;
    }
    
    int inline ask(int x) {
        int res = 0;
        for (; x; x -= x & -x) res += c[x];
        return res;
    }
    
    void dfs(int u) {
        dfn[u] = ++dfncnt, sz[u] = 1;
        for (int i = head[u]; i; i = e[i].next) {
            int v = e[i].v;
            if (v == fa[u])
                continue;
            fa[v] = u;
            dfs(v);
            sz[u] += sz[v];
        }
    }
    
    int inline query(int x) { return ask(dfn[x] + sz[x] - 1) - ask(dfn[x] - 1) + 1; }
    
    int main() {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) rt[i] = i;
        for (int i = 1; i <= m; i++) {
            char c[2];
            scanf("%s%d%d", c, A + i, B + i);
            opt[i] = c[0] == 'A' ? 0 : 1;
            if (!opt[i])
                addEdge(A[i], B[i]), addEdge(B[i], A[i]);
        }
        for (int i = 1; i <= n; i++)
            if (!dfn[i])
                dfs(i);
        for (int i = 1; i <= m; i++) {
            int x = A[i], y = B[i];
            if (y == fa[x])
                swap(x, y);
            if (opt[i] == 0) {
                // 连接
                rt[find(y)] = find(x);
                x = find(x);
                int v = query(y);
                add(dfn[fa[x]], -v), add(dfn[fa[y]], v);
            } else {
                // 查询
                x = find(x);
                printf("%lld
    ", (LL)query(y) * (query(x) - query(y)));
            }
        }
        return 0;
    }
    
  • 相关阅读:
    Python三维绘图--Matplotlib colorbar生成
    Python三维绘图--Matplotlib
    VIM剪切板的使用
    三维点云网络PointNet——模型及代码分析
    ECCV2018--点云匹配
    hdu 1905 小数化分数2
    hdu 1755 A Number Puzzle
    hdu 1796 How many integers can you find
    hdu 1452 Happy 2004
    hdu 2837 Calculation
  • 原文地址:https://www.cnblogs.com/dmoransky/p/12546151.html
Copyright © 2011-2022 走看看