首页 > 其他 > 详细

51nod2553 双重祖先

时间:2019-11-03 13:56:16      阅读:93      评论:0      收藏:0      [点我收藏+]

题意

给定两颗有根树,两颗树均有 \(n\) 个节点,且跟均为 \(1\) 号点

问有多少对 \((u,v)\) 满足在给定的两颗树中 \(u\) 均为 \(v\) 的祖先


解法

先重链剖分第一颗树,处理出剖分序后在第二颗树上 \(dfs\)

每 \(dfs\) 到一个点就把其加入第一颗树对应的剖分序的位置,可以用树状数组维护

那么假设现在 \(dfs\) 到的点为点 \(x\),那么其祖先一定都在树状数组中,那么只要在第一颗树上查询 \(x\) 到根上 \(1\) 的个数即可。这里的 \(1\) 代表着既在第一颗树上是 \(x\) 的祖先,又在第二颗树上是 \(x\) 的祖先


代码

#include <cstdio>
#include <vector>

using namespace std;

const int MAX_N = 1e5 + 10;

void dfs_1(int x);
void dfs_2(int x, int tp);

int N;

long long ans;

int sz[MAX_N], fa[MAX_N], son[MAX_N], dep[MAX_N], dfn[MAX_N], top[MAX_N], pos[MAX_N], Id;

vector<int> e[MAX_N], g[MAX_N];

struct BIT {
    int c[MAX_N];
    void insert(int x, int v) {
        for (; x && x <= N; x += x & -x)  c[x] += v;
    }
    int query(int x, int res = 0) {
        for (; x; x -= x & -x)  res += c[x];
        return res;
    }
} tr;

int query(int x) {
    int res = 0;
    while (x) {
        res += tr.query(pos[x]) - tr.query(pos[top[x]] - 1);
        x = fa[top[x]];
    }
    return res;
}

void DFS(int x, int lst) {
    ans += query(fa[x]);
    tr.insert(pos[x], 1);
    for (int i = 0, s = g[x].size(); i < s; ++i) {
        int v = g[x][i];
        if (v ^ lst)  DFS(v, x);
    }
    tr.insert(pos[x], -1);
}

int main() {
    
    scanf("%d", &N);
    
    int u, v;
    for (int i = 1; i < N; ++i) {
        scanf("%d%d", &u, &v);
        e[u].push_back(v), e[v].push_back(u);
    }
    
    for (int i = 1; i < N; ++i) {
        scanf("%d%d", &u, &v);
        g[u].push_back(v), g[v].push_back(u);   
    }
    
    dfs_1(1);
    dfs_2(1, 1);
    
    DFS(1, 0);
    
    printf("%lld\n", ans);
    
    return 0;   
}

void dfs_1(int x) {
    sz[x] = 1;
    for (int i = 0, s = e[x].size(); i < s; ++i) {
        int v = e[x][i];
        if (v ^ fa[x]) {
            fa[v] = x, dep[v] = dep[x] + 1, dfs_1(v), sz[x] += sz[v];
            if (sz[v] > sz[son[x]])  son[x] = v;
        }
    }
}

void dfs_2(int x, int tp) {
    top[x] = tp, dfn[++Id] = x, pos[x] = Id;
    if (son[x]) {
        dfs_2(son[x], tp);
        for (int i = 0, s = e[x].size(); i < s; ++i) {
            int v = e[x][i];
            if (!pos[v])  dfs_2(v, v);
        }
    }
}

51nod2553 双重祖先

原文:https://www.cnblogs.com/VeniVidiVici/p/11785480.html

踩
(0)
赞
(0)
   
举报
评论 一句话评论(0)
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!