Hdu4547CD操作离线lca

题意:根目录能一次到达其任意子目录,子目录返回上一层目录需要一次,给出目录关系,问从某个目录到某个目录最少要多少步。

操作数 ,就是起点到最近公共祖先的距离。

然后讨论下,如果最近公共祖先等于终点,那么答案就是起点到祖先的高度差 ,否则就是高度差加一 。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<string>
using namespace std;

const int maxn = 111111;

int father[maxn];

map<pair<int, int>, int> ans;
vector<int> q[maxn];
int getfather(int x)
{
    if (father[x] != x) return father[x] = getfather(father[x]);
    return father[x];
}
int len, head[maxn];
int l[maxn], r[maxn];
struct Node
{
    int to; int next;
}e[maxn * 2];
int deep[maxn];
int color[maxn];
void add(int from, int to)
{
    e[len].to = to;
    e[len].next = head[from];
    head[from] = len++;
}

int un(int x, int y)
{
    int fx = getfather(x); int fy = getfather(y);
    father[fy] = fx;
}

void dfs(int x)
{
    for (int i = head[x]; i != -1; i = e[i].next){
        int cc = e[i].to;
        dfs(cc);
        un(x, cc);
    }
    color[x] = 1;
    for (int i = 0; i < q[x].size(); i++){
        int t = q[x][i];
        if (color[t]){
            int gg = getfather(t);
            ans[make_pair(x, t)] = gg;
            ans[make_pair(t, x)] = gg;
        }
    }
}

void build(int root, int dep)
{
    deep[root] = dep;
    for (int i = head[root]; i != -1; i = e[i].next){
        int cc = e[i].to;
        build(cc, dep + 1);
    }
}
int gg[maxn];
void init(int n)
{
    len = 0;
    memset(head, -1, sizeof(head));
    memset(color, 0, sizeof(color));
    memset(gg, 0, sizeof(gg));
    for (int i = 1; i <= n; i++)
        father[i] = i;
    for (int i = 1; i <= n; i++)
        q[i].clear();

}

int main()
{
    int T;
    int n, M;
    char a[100], b[100];
    cin >> T;
    map<string, int> m;
    while (T--){
        int cnt = 1;
        m.clear();
        scanf("%d%d", &n, &M);
        init(n);
        for (int i = 0; i < n - 1; i++){
            scanf("%s%s", a, b); int c; int d;
            if (!m[a]) m[a] = cnt++;
            if (!m[b]) m[b] = cnt++;
            c = m[a]; d = m[b];
            add(d, c); gg[c] = 1;
        }
        int root;
        for (int i = 1; i <= n; i++)
        if (!gg[i]){
            root = i; break;
        }
        build(root, 1);
        for (int i = 0; i < M; i++){
            scanf("%s%s", a, b);
            int c = m[a]; int d = m[b];
            l[i] = c; r[i] = d;
            q[c].push_back(d);
            q[d].push_back(c);
        }
        dfs(root);
        for (int i = 0; i < M; i++){
            int t = ans[make_pair(l[i], r[i])];
            if (t == r[i]){
                printf("%d\n", deep[l[i]] - deep[t]);
            }
            else{
                printf("%d\n", deep[l[i]] - deep[t] + 1);
            }
        }
    }
    return 0;
}
时间: 2024-08-25 04:34:47

Hdu4547CD操作离线lca的相关文章

POJ 3728 离线 LCA

题意很简单 给一个树(n < 5w) 每个点有个权值,代表商品价格 若干个询问(5w) 对每个询问,问的是从u点走到v点(简单路径),商人在这个路径中的某点买入商品,然后在某点再卖出商品,   最大可能是多少 注意一条路径上只能买卖一次,先买才能卖 用的方法是离线LCA,在上面加了一些东西 对于一个询问, 假设u,v的LCA是f 那么有三种可能, 一个是从u到f 买卖了. 一个是从f到v买卖了,  一个是从u到f之间买了,从v到f卖了 从u到f 我们称为up,  从f到v我们称为down,而从u

HDU 5452(离线LCA,树形dp

题目:给出一个图和它的一个生成树,要求删除生成树上的一条边和若干其他边,使得图不连通.求能删除的最小边数. 思路:考虑dp,对于树上的一条边,删除之后,还需要删除的边的数目就是从这个节点的子树连向其他子树或祖先节点的边数.那么对于一棵子树来说这个统计数目就等于其子树的数目之和减去它的子树之间的边数.减的这一部分可以在tarjan离线LCA算法中实现. /* * @author: Cwind */ //#pragma comment(linker, "/STACK:102400000,102400

HDU 2586 How far away ? 离线lca模板题

How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 8712    Accepted Submission(s): 3047 Problem Description There are n houses in the village and some bidirectional roads connecting

HDU 5044 离线LCA算法

昨天写了HDU 3966 ,本来这道题是很好解得,结果我想用离线LCA 耍一把,结果发现离线LCA 没理解透,错了好多遍,终得AC ,这题比起 HDU 3966要简单,因为他不用动态查询.但是我还是错了好多遍  T^T... http://acm.split.hdu.edu.cn/showproblem.php?pid=5044 不多说了  思想不是很清楚的可以看一看我的上一篇博文 HDU 3966 直接贴代码 1 #include<iostream> 2 #include<stdio.

hdoj 2586 How far away ? 【Tarjan离线LCA】

题目:hdoj 2586 How far away ? 题意:给出一个有权树,求任意两点的之间的距离. 分析:思想就是以一个点 root 作为跟变成有根数,然后深搜处理处所有点到跟的距离.求要求的两个点的LCA(最近公共祖先), 然后ans = dis[x] + dis[y] - 2 * dis[LCA(x,y)],可以画图分析一下就知道. 求LCA我用的是Tarjan离线lca,由于询问次数很多,所以这个比较快. AC代码: #include <iostream> #include <

hihoCoder #1067 : 最近公共祖先&#183;二 [ 离线LCA tarjan ]

传送门: #1067 : 最近公共祖先·二 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上上回说到,小Hi和小Ho用非常拙劣——或者说粗糙的手段山寨出了一个神奇的网站,这个网站可以计算出某两个人的所有共同祖先中辈分最低的一个是谁.远在美国的他们利用了一些奇妙的技术获得了国内许多人的相关信息,并且搭建了一个小小的网站来应付来自四面八方的请求. 但正如我们所能想象到的……这样一个简单的算法并不能支撑住非常大的访问量,所以摆在小Hi和小Ho面前的无非两种选择: 其一是

hdu 2586 How far away ?(Tarjan离线LCA)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 题意:对于一个有 n 个节点的图,有 n - 1 条无向边,权值给出.有 m 个查询, 每个查询 a b 表示询问 a b 两节点间的距离. 思路: 把这个联通图以树的形式表现出来,取任意两点,假设其最近公共祖先(Least Common Ancestors)为 lca,则两点间的距离等于: dis(a, b) = dis(a, root) + dis(b, root) - 2 * dis(r

离线LCA学习

题目1 : 最近公共祖先·二 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上上回说到,小Hi和小Ho用非常拙劣--或者说粗糙的手段山寨出了一个神奇的网站,这个网站可以计算出某两个人的所有共同祖先中辈分最低的一个是谁.远在美国的他们利用了一些奇妙的技术获得了国内许多人的相关信息,并且搭建了一个小小的网站来应付来自四面八方的请求. 但正如我们所能想象到的--这样一个简单的算法并不能支撑住非常大的访问量,所以摆在小Hi和小Ho面前的无非两种选择: 其一是购买更为昂贵的

2333: [SCOI2011]棘手的操作[离线线段树]

2333: [SCOI2011]棘手的操作 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2325  Solved: 909[Submit][Status][Discuss] Description 有N个节点,标号从1到N,这N个节点一开始相互不连通.第i个节点的初始权值为a[i],接下来有如下一些操作: U x y: 加一条边,连接第x个节点和第y个节点 A1 x v: 将第x个节点的权值增加v A2 x v: 将第x个节点所在的连通块的所有