hihoCoder week17 最近公共祖先·三 lca st表

记录dfs序列,dfn[tot] 记录第tot次访问的节点

然后查两点在dfs序中出现的第一次 id[u] id[v]

然后  找 dep[k] = min( dep[i] ) {i 属于 [id[u], id[v]]}

最后dfn[k] 就是所求..

感觉弄来弄去 就是 在映射... 无非就是 求一段序列深度最小的节点编号

#include <bits/stdc++.h>
using namespace std;

const int N = 2e5+10;

int n, cnt, tot, dp[N][21]; // dp[i][j] [i, i+(1<<j)-1]
vector<int> G[N]; map<string ,int> mp;
string s1,s2,s[N];

int dfn[N], id[N], dep[N];
int getId(string str)
{
    if(mp[str])
        return mp[str];
    mp[str] = ++cnt;
    s[cnt] = str;
    return cnt;
}

void dfs(int u,int fa,int d)
{
    id[u] = tot;
    dfn[tot] = u;
    dep[tot++] = d;

    for(int i=0; i<G[u].size(); i++) {
        int v = G[u][i];
        dfs(v, u, d+1);
        dfn[tot] = u;
        dep[tot++] = d;
    }
    return ;
}

void st_init(int sz)
{
    for(int i=1; i<=sz; i++)
        dp[i][0] = i;
    for(int j=1; (1<<j)<=sz; j++)
    {
        for(int i=1; i+(1<<j)-1<=sz; i++)
        {
            int x = dp[i][j-1];
            int y = dp[i+(1<<(j-1))][j-1];
            if(dep[x] < dep[y])
                dp[i][j] = x;
            else
                dp[i][j] = y;
        }
    }
}

void init()
{
    tot = 1;
    dfs(1, 0, 0);
    st_init(tot-1);
}

int query(int u,int v)
{
    u = id[u], v = id[v];
    if(v < u)
        swap(v,u);
    int t = log2(v-u+1);
    int x = dp[u][t];
    int y = dp[v-(1<<t)+1][t];
    if(dep[x] < dep[y])
        return x;
    else
        return y;
}
int main()
{
    freopen("in.txt","r",stdin);
    ios::sync_with_stdio(0);
    cin >> n;
    for(int i=0; i<n; i++) {
        cin >> s1 >> s2;
        int u = getId(s1);
        int v = getId(s2);
        G[u].push_back(v);
    }
    init();
    int m; cin >> m;
    for(int i=0; i<m; i++) {
        cin >> s1 >> s2;
        int u = getId(s1);
        int v = getId(s2);
        int x = dfn[query(u,v)];
        cout << s[x] <<"\n";
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Draymonder/p/10010241.html

时间: 2024-11-10 08:38:00

hihoCoder week17 最近公共祖先·三 lca st表的相关文章

hihocoder1069最近公共祖先&#183;三(LCA在线算法--DFS+RMQ-ST)

树上任意两点的最近祖先,必定就是这两个节点的最短路径上深度最小的那个点. 例如:下图中,节点7和5,其最短路径为7--4--1--5, 这条路径上深度最小的点为节点1,其深度为1.节点1即为节点7和5的LCA. 因此,要找到任意两个节点的LCA,只需要先找到上述最短路径,再找到最短路径中深度最小的点.而这下面所述LCA在线算法所做的事. LCA在线算法描述(以上图为例): 1.获得“最短路径”(并不是真正的一条路径,包含其他节点,但不影响算法的正确性) 采用DFS遍历整棵树,得到以下数据: (1

hihoCoder#1069 最近公共祖先&#183;三

原题地址 根据提示用Spase Table做 将Tree先展成List,因为数组长度等于边数的2倍,树中边数等于节点数-1,所以List数组只要开2倍节点数大小即可 WA了几次,原来是查询的时候出现左边界大于右边界的情况,所以这种情况要颠倒一下 代码: 1 #include <iostream> 2 #include <vector> 3 #include <string> 4 #include <map> 5 6 using namespace std;

最近公共祖先(lca)

囧啊囧. lca的求法太多了 倍增,tarjan,st,lct,hld.... 后边三个我就不写了,其中st我没写过,估计用不上,在线用倍增,离线用tarjan就行了. 嗯. 第一种,倍增(nlogn,在线): 倍增的思想用在树上,即可以求出lca. 我们维护二维数组,f[i][j],表示i号点的第2^j号祖先,显然2^0=1也就是f[i][0]就是他的父亲 我们需要用dfs维护一个深度数组(求lca需要用) 还需要倍增求出所有的f[i][j],学过st的都应该知道,在这里f[i][j]=f[

hihoCoder_#1069_最近公共祖先&#183;三(RMQ-ST模板)

#1069 : 最近公共祖先·三 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上上回说到,小Hi和小Ho使用了Tarjan算法来优化了他们的"最近公共祖先"网站,但是很快这样一个离线算法就出现了问题:如果只有一个人提出了询问,那么小Hi和小Ho很难决定到底是针对这个询问就直接进行计算还是等待一定数量的询问一起计算.毕竟无论是一个询问还是很多个询问,使用离线算法都是只需要做一次深度优先搜索就可以了的. 那么问题就来了,如果每次计算都只针对一个询问进行的话

洛谷P3379 【模板】最近公共祖先(LCA)

P3379 [模板]最近公共祖先(LCA) 152通过 532提交 题目提供者HansBug 标签 难度普及+/提高 提交  讨论  题解 最新讨论 为什么还是超时.... 倍增怎么70!!题解好像有倍- 题面这个地方写错了 无论是用RMQ+dfs还是tarjan- 为什么我的倍增超时了 求助!为什么只有70分 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接

【原创】洛谷 LUOGU P3379 【模板】最近公共祖先(LCA) -&gt; 倍增

P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询问的结果. 输入输出样例 输入

洛谷 P3379 【模板】最近公共祖先(LCA) 如题

P3379 [模板]最近公共祖先(LCA) 时空限制1s / 512MB 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询

最近公共祖先(LCA)---tarjan算法

LCA(最近公共祖先).....可惜我只会用tarjan去做 真心感觉tarjan算法要比倍增算法要好理解的多,可能是我脑子笨吧略略略 最近公共祖先概念:在一棵无环的树上寻找两个点在这棵树上深度最大的公共的祖先节点,也就是离这两个点最近的祖先节点. 最近公共祖先的应用:求解两个有且仅有一条确定的最短路径的路径 举个例子吧,如下图所示4和5的最近公共祖先是2,5和3的最近公共祖先是1,2和1的最近公共祖先是1. 这就是最近公共祖先的基本概念了,那么我们该如何去求这个最近公共祖先呢? Tarjan介

P3379 【模板】最近公共祖先(LCA)(dfs序)

P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询问的结果. 输入输出样例 输入