• 【模板】最近公共祖先(LCA)


    题意简述

    给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。

    题解思路

    1.倍增,先将两个点跳至同一高度,再同时往上跳 ( 2 ^ n )高度

    2.tarjan,离线,先将所有询问存起来,dfs一遍

    3.树链剖分

    代码(倍增)

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    int n, m, s, u, v, cnt;
    int h[501000], to[1001000], nxt[1001000], dep[501000], lg[501000];
    int f[501000][25];
    inline void add_edge(const int& u, const int& v)
    {
        to[++cnt] = v;
        nxt[cnt] = h[u];
        h[u] = cnt;
    }
    void dfs(const int& x)
    {
        for (register int i = 0; f[x][i]; ++i) f[x][i + 1] = f[f[x][i]][i];
        for (register int i = h[x]; i; i = nxt[i])
            if (to[i] ^ f[x][0])
            {
                dep[to[i]] = dep[x] + 1;
                f[to[i]][0] = x;
                dfs(to[i]);
            }
    }
    inline int lca(int x, int y)
    {
        if (dep[x] < dep[y]) swap(x, y);
        while (dep[x] > dep[y]) x = f[x][lg[dep[x] - dep[y]]];
        if (x == y) return x;
        for (register int i = lg[dep[x]] + 1; i--;)
            if (f[x][i] ^ f[y][i])
                x = f[x][i], y = f[y][i];
        return f[x][0];
    }
    int main()
    {
        scanf("%d%d%d", &n, &m, &s);
        for (register int i = 2; i <= n; ++i)
        {
            lg[i] = lg[i >> 1] + 1;
            scanf("%d%d", &u, &v);
            add_edge(u, v);
            add_edge(v, u);
        }
        dfs(s);
        for (register int i = 1; i <= m; ++i)
        {
            scanf("%d%d", &u, &v);
            printf("%d
    ", lca(u, v));
        }
    }
    

    代码(tarjan)

    #include <cstdio>
    int n, m, s, u, v, cnt, N;
    int h[501000], to[2001000], nxt[2001000], ans[501000], fa[501000];
    inline void add_edge(const int& u, const int& v)
    {
        to[++cnt] = v;
        nxt[cnt] = h[u];
        h[u] = cnt;
    }
    int find(const int& x) {return x ^ fa[x] ? fa[x] = find(fa[x]) : x;}
    void dfs(int x)
    {
        fa[x] = x;
        for (register int i = h[x]; i; i = nxt[i])
            if (i < N && !fa[to[i]]) dfs(to[i]), fa[to[i]] = x;
            else if (i >= N && fa[to[i]]) ans[(i - N) >> 1] = find(to[i]);
    }
    int main()
    {
        scanf("%d%d%d", &n, &m, &s);
        N = 2 * n - 1;
    	n += m;
        for (register int i = 1; i < n; ++i)
        {
            scanf("%d%d", &u, &v);
            add_edge(u, v); add_edge(v, u);
        }
        dfs(s);
        for (register int i = 0; i < m; ++i) printf("%d
    ", ans[i]);
    }
    

    代码(树链剖分)

    #include <cstdio>
    #include <algorithm> 
    int n, m, s, u, v, cnt;
    int h[600000], nxt[1100000], to[1100000];
    int f[600000], sz[600000], dep[600000], hvs[600000], top[600000];
    inline void add_edge(const int& u, const int& v)
    {
    	nxt[++cnt] = h[u];
    	to[cnt] = v;
    	h[u] = cnt; 
    }
    void dfs1(const int& u)
    {
    	sz[u] = 1;
    	for (register int i = h[u]; i; i = nxt[i])
    		if (to[i] ^ f[u])
    		{
    			dep[to[i]] = dep[u] + 1;
    			f[to[i]] = u;
    			dfs1(to[i]);
    			sz[u] += sz[to[i]];
    			if (!hvs[u] || sz[to[i]] > sz[hvs[u]]) hvs[u] = to[i];
    		}
    }
    void dfs2(const int& u, const int& tp)
    {
    	top[u] = tp;
    	if (hvs[u]) dfs2(hvs[u], tp);
    	for (register int i = h[u]; i; i = nxt[i])
    		if (to[i] ^ f[u] && to[i] ^ hvs[u])
    			dfs2(to[i], to[i]);
    }
    inline int query(int u, int v)
    {
    	for (; top[u] ^ top[v]; u = f[top[u]])
    		if (dep[top[u]] < dep[top[v]])
    			std::swap(u, v);
    	return dep[u] < dep[v] ? u : v;
    }
    int main()
    {
    	scanf("%d%d%d", &n, &m, &s);
    	for (register int i = 1; i < n; ++i)
    	{
    		scanf("%d%d", &u, &v);
    		add_edge(u, v); add_edge(v, u);
    	}
    	f[s] = s;
    	dfs1(s); dfs2(s, s);
    	for (register int i = 1; i <= m; ++i)
    	{
    		scanf("%d%d", &u, &v);
    		printf("%d
    ", query(u, v));
    	}
    }
    
  • 相关阅读:
    uva10256
    uva11168
    zoj2318
    hdu6121
    hdu6127
    bzoj3957: [WF2011]To Add or to Multiply
    bzoj4377: [POI2015]Kurs szybkiego czytania
    bzoj3137: [Baltic2013]tracks
    bzoj4069: [Apio2015]巴厘岛的雕塑
    bzoj4169: Lmc的游戏
  • 原文地址:https://www.cnblogs.com/xuyixuan/p/9696617.html
Copyright © 2020-2023  润新知