题目描述

【传送门】

题目大意

给一棵树,有两种操作:

  • 求(u,v)路径的距离。
  • 求以u为起点,v为终点的第k的节点.

分析

比较简单的倍增LCA模板题。
首先对于第一问,我们只需要预处理出根节点到各个节点之间的距离,然后倍增LCA求解就可以了。
那么第二问我WA了6发,原来是眼瞎和手残打错了两个字符错掉了。
我们将问题分成3个部分:

  • LCA是第k个
  • 第k个在u到LCA的路径上
  • 第k个在LCA到v的路径上。

首先如果LCA是第k个,那么直接输出。
如果是第二种情况,那么从u开始做倍增,每一次k-(1<<i)就可以了。
小细节:只能将k变成1,模拟可证明。
第三种情况,那么我们的答案就是从v的第(dep[u]+dep[v]-2*dep[lca]+2),模拟可得该式。

ac代码

#include <bits/stdc++.h>
#define ll long long
#define ms(a, b) memset(a, b, sizeof(a))
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
template <typename T>
inline void read(T &x) {
    x = 0; T fl = 1;
    char ch = 0;
    while (ch < '0' || ch > '9') {
        if (ch == '-') fl = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    x *= fl;
}
#define N 20005
struct edge {
    int to, nt;
    ll w;
}E[N << 1];
ll dis[N];
int f[N][31], H[N], dep[N];
int cnt, n;
void add_edge(int u, int v, ll w) {
    E[++ cnt] = (edge){v, H[u], w};
    H[u] = cnt;
}
void dfs(int u, int fa, int dist) {
    f[u][0] = fa;
    dis[u] = dist;
    for (int i = 1; i <= 30; i ++)
        f[u][i] = f[f[u][i - 1]][i - 1];
    for (int e = H[u]; e; e = E[e].nt) {
        int v = E[e].to;
        if (v == fa) continue;
        dep[v] = dep[u] + 1;
        dfs(v, u, dist + E[e].w);
    }
}
int lca(int u, int v) {
    if (dep[u] < dep[v]) swap(u, v);
    for (int i = 30; i >= 0; i --)
        if (dep[v] <= dep[f[u][i]]) u = f[u][i];
    if (u == v) return u;
    for (int i = 30; i >= 0; i --)
        if (f[u][i] != f[v][i]) {
            u = f[u][i];
            v = f[v][i];
        }
    return f[u][0];
}
int solve(int u, int v, int k) {
    int Lca = lca(u, v);
    if (dep[u] - dep[Lca] + 1 == k) return Lca;
    else {
        if (dep[u] - dep[Lca] + 1 > k) {
            for (int i = 30; i >= 0; i --)
                if (k - 1 >= (1 << i)) k -= (1 << i), u = f[u][i];
            return u;
        }
        else {
            k = dep[u] + dep[v]- dep[Lca] * 2 - k + 2;
            for (int i = 30; i >= 0; i --)
                if (k - 1 >= (1 << i)) k -= (1 << i), v = f[v][i];
            return v;
        }
    }
}
int main() {
    int cas;
    read(cas);
    char opt[10];
    while (cas --) {
        cnt = 0;
        ms(H, 0);
        ms(dis, 0);
        ms(dep, 0);
        ms(f, 0);
        read(n);
        for (int i = 1; i < n; i ++) {
            int u, v;  ll w;
            read(u); read(v); read(w);
            add_edge(u, v, w);
            add_edge(v, u, w);
        }
        dep[1] = 1;
        dfs(1, 0, 0);
        while (1) {
            scanf("%s", opt);
            if (opt[1] == 'O') break;
            if (opt[0] == 'D') {
                int u, v;
                read(u); read(v);
                int Lca = lca(u, v), res;
                printf("%lld\n", dis[u] + dis[v] - dis[Lca] * 2);
            }
            else {
                int u, v, k;
                read(u); read(v); read(k);
                printf("%d\n", solve(u, v, k));
            }
        }
    }
    return 0;
}

[SPOJ913]QTREE2 - Query on a tree II【倍增LCA】的更多相关文章

  1. spoj 913 Query on a tree II (倍增lca)

    Query on a tree II You are given a tree (an undirected acyclic connected graph) with N nodes, and ed ...

  2. 【SPOJ QTREE2】QTREE2 - Query on a tree II(LCA)

    You are given a tree (an undirected acyclic connected graph) with N nodes, and edges numbered 1, 2, ...

  3. Query on a tree II 倍增LCA

    You are given a tree (an undirected acyclic connected graph) with N nodes, and edges numbered 1, 2, ...

  4. LCA SP913 QTREE2 - Query on a tree II

    SP913 QTREE2 - Query on a tree II 给定一棵n个点的树,边具有边权.要求作以下操作: DIST a b 询问点a至点b路径上的边权之和 KTH a b k 询问点a至点 ...

  5. SP913 QTREE2 - Query on a tree II

    思路 第一个可以倍增,第二个讨论在a到lca的路径上还是lca到b的路径上, 倍增即可 代码 #include <cstdio> #include <algorithm> #i ...

  6. SPOJ QTREE2 Query on a tree II

    传送门 倍增水题…… 本来还想用LCT做的……然后发现根本不需要 //minamoto #include<bits/stdc++.h> using namespace std; #defi ...

  7. SPOJ COT2 - Count on a tree II(LCA+离散化+树上莫队)

    COT2 - Count on a tree II #tree You are given a tree with N nodes. The tree nodes are numbered from  ...

  8. QTREE2 spoj 913. Query on a tree II 经典的倍增思想

    QTREE2 经典的倍增思想 题目: 给出一棵树,求: 1.两点之间距离. 2.从节点x到节点y最短路径上第k个节点的编号. 分析: 第一问的话,随便以一个节点为根,求得其他节点到根的距离,然后对于每 ...

  9. SPOJ913 Query on a tree II

    Time Limit: 433MS   Memory Limit: 1572864KB   64bit IO Format: %lld & %llu Description You are g ...

随机推荐

  1. Django model操作

    一.各种查询统计操作   def all(self) # 获取所有的数据对象 def filter(self, *args, **kwargs) # 条件查询 # 条件可以是:参数,字典,Q def ...

  2. 打开指定测试App的指定Activity

    那究竟应该如何让appium去自动找到指定的APP和指定的Activity呢?想要打开指定的App,需要知道App的包名,同样想要打开指定Activity也需要知道其名,如何获取? 1.问公司的开发人 ...

  3. 软工网络15团队作业4——Alpha阶段敏捷冲刺

    Deadline: 2018-4-29 10:00PM,以提交至班级博客时间为准. 根据以下要求,团队在日期区间[4.16,4.29]内,任选8天进行冲刺,冲刺当天晚10点前发布一篇随笔,共八篇. 另 ...

  4. IntelliJ IDEA/WebStrom破解及JDK配置

    title: IntelliJ IDEA/WebStrom破解及JDK配置 (一)破解 破解步骤 第一步:下载破解补丁 第二步:修改配置文件 第三步:重启IntelliJ IDEA/WebStrom填 ...

  5. GitHub创建仓库,并与git本地仓库关联

    登录后头像右上角点击: 起名再create 后 会跳转到下面页面: 先在git上复制执行第一条指令,创建一个readme文档 然后再用第二条初始化仓库 第三步将readme文档添加至暂存区 然后提交一 ...

  6. linux audit审计(6)--audit永久生效的规则配置

    定义reboot系统后,仍然生效的审计规则,有两种办法: 1.直接写入/etc/audit/audit.rules文件中,在service文件中需要加入ExecStartPost=-/sbin/aud ...

  7. python3 阿里云控制SLB权重

    一.配置好RAM账号的权限(SLB管理权限) 二.安装依赖 pip3 install aliyun-python-sdk-slb pip3 install aliyun-python-sdk-core ...

  8. Java集合和数组的区别

    参考:Java集合和数组的区别 集合和容器都是Java中的容器. 区别 数组特点:大小固定,只能存储相同数据类型的数据 集合特点:大小可动态扩展,可以存储各种类型的数据   转换 数组转换为集合: A ...

  9. 和docket的第一次亲密接触

    很久很久以前,第一次听说docker时,感觉很高大上,同时自我感觉会很难.所以一直没有详细了解.前一段时间偶尔看到关于docker的详细介绍,于是乎来了兴趣.自已折腾了一下,发现不是想象中的那么难. ...

  10. Zend Framework2从入门到精通

    1. 下载安装zf2的web程序 步骤: 第一步,保证得到一个基本的zf2框架 直接从官网下载并解压即可:http://www.zendframework.org.cn/downloads/lates ...