FJUT 聪明的商人(树上倍增)题解

思路:求树上两点的距离,显然是dep[u] + dep[v] - 2 * dep[lca],用树上倍增去写。

参考:树上倍增的写法和应用(详细讲解,新手秒懂)

代码:

#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
typedef long long ll;
const int maxn = 50000 + 10;
const int seed = 131;
const ll MOD = 1e9 + 7;
const ll INF = 1e17;
using namespace std;
struct Edge{
    int to, next;
}edge[maxn << 2];
int fa[maxn][100], dep[maxn], head[maxn], tot, maxf;
void addEdge(int u, int v){
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot++;
}
void dfs(int x, int pre, int deep){
    dep[x] = deep;
    fa[x][0] = pre;
    for(int i = 1; i <= maxf; i++){
        if(fa[x][i - 1] != -1){
            fa[x][i] = fa[fa[x][i - 1]][i - 1];
        }
        else break;
    }
    for(int i = head[x]; i != -1; i = edge[i].next){
        int v = edge[i].to;
        if(v != pre){
            dfs(v, x, deep + 1);
        }
    }
}
int LCA(int u, int v){
    if(dep[u] < dep[v]) swap(u, v);
    int dis = dep[u] - dep[v];
    for(int i = 0; i <= maxf; i++){
        if((1 << i) & dis)
            u = fa[u][i];
    }
    if(u == v) return u;
    for(int i = maxf; i >= 0; i--){
        if(fa[u][i] != fa[v][i]){
            u = fa[u][i];
            v = fa[v][i];
        }
    }
    return fa[u][0];
}

void init(){
    maxf = 30;
    memset(head, -1, sizeof(head));
    memset(fa, -1, sizeof(fa));
    tot = 0;
}
int main(){
    int n, m, w;

    while(~scanf("%d%d%d", &n, &m, &w)){
        init();
        for(int i = 0; i < n - 1; i++){
            int a, b;
            scanf("%d%d", &a, &b);
            addEdge(a, b);
            addEdge(b, a);
        }
        dfs(0, -1, 0);
        for(int i = 0; i < m; i++){
            int p, q, v;
            scanf("%d%d%d", &p, &q, &v);
            int lca = LCA(p , q);
            int dis = dep[p] + dep[q] - 2 * dep[lca];
            if(v - dis * w >= 0){
                printf("%d\n", v - dis * w);
            }
            else{
                printf("pass\n");
            }
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/KirinSB/p/9937648.html

时间: 2024-10-13 14:08:10

FJUT 聪明的商人(树上倍增)题解的相关文章

【树上倍增】【分类讨论】水果姐逛水果街Ⅱ

3305 水果姐逛水果街Ⅱ 时间限制: 2 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 水果姐第二天心情也很不错,又来逛水果街. 突然,cgh又出现了.cgh施展了魔法,水果街变成了树结构(店与店之间只有一条唯一的路径). 同样还是n家水果店,编号为1~n,每家店能买水果也能卖水果,并且同一家店卖与买的价格一样. cgh给出m个问题,每个问题要求水果姐从第x家店出发到第y家店,途中只能选一家店买一个水果,然后选一家店(可以是同一家店,

【bzoj4281】[ONTAK2015]Zwi?zek Harcerstwa Bajtockiego 树上倍增+LCA

题目描述 给定一棵有n个点的无根树,相邻的点之间的距离为1,一开始你位于m点.之后你将依次收到k个指令,每个指令包含两个整数d和t,你需要沿着最短路在t步之内(包含t步)走到d点,如果不能走到,则停在最后到达的那个点.请在每个指令之后输出你所在的位置. 输入 第一行包含三个正整数n,m,k(1<=m<=n<=1000000,1<=k<=1000000). 接下来n-1行,每行包含两个正整数x,y(1<=x,y<=n),描述一条树边. 接下来k行,每行两个整数d,t

HDU 4822 Tri-war(LCA树上倍增)(2013 Asia Regional Changchun)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4822 Problem Description Three countries, Red, Yellow, and Blue are in war. The map of battlefield is a tree, which means that there are N nodes and (N – 1) edges that connect all the nodes. Each country

【bzoj3779】重组病毒 LCT+树上倍增+DFS序+树状数组区间修改区间查询

题目描述 给出一棵n个节点的树,每一个节点开始有一个互不相同的颜色,初始根节点为1. 定义一次感染为:将指定的一个节点到根的链上的所有节点染成一种新的颜色,代价为这条链上不同颜色的数目. 现有m次操作,每次为一下三种之一: RELEASE x:对x执行一次感染: RECENTER x:把根节点改为x,并对原来的根节点执行一次感染: REQUEST x:询问x子树中所有节点感染代价的平均值. 输入 输入的第一行包含两个整数n和m,分别代表局域网中计算机的数量,以及操作和询问的总数.接下来n-1行,

【codeforces666E】Forensic Examination 广义后缀自动机+树上倍增+线段树合并

题目描述 给出 $S$ 串和 $m$ 个 $T_i$ 串,$q$ 次询问,每次询问给出 $l$ .$r$ .$x$ .$y$ ,求 $S_{x...y}$ 在 $T_l,T_{l+1},...,T_r$ 中的哪一个里出现次数最多,输出出现次数最多的串编号(如果有多个则输出编号最小的)以及相应出现次数. $|S|,q\le 5\times 10^5$ ,$\sum\limits_{i=1}^m|T_i|\le 5\times 10^4$ . 题解 广义后缀自动机+树上倍增+线段树合并 对 $S$

luogu1081 开车旅行 树上倍增

题目大意 小A和小B决定利用假期外出旅行,他们将想去的城市从1到N编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市i 的海拔高度为Hi,城市i 和城市j 之间的距离d[i,j]恰好是这两个城市海拔高度之差的绝对值,即d[i,j] = |Hi – Hj|. 旅行过程中,小A和小B轮流开车,第一天小A开车,之后每天轮换一次.他们计划选择一个城市S作为起点,一直向东行驶,并且最多行驶X公里就结束旅行.小A和小B的驾驶风格不同,小B总是沿着前进方向选择一个最近的城市作

【BZOJ 3551】[ONTAK2010] Peaks加强版 Kruskal重构树+树上倍增+主席树

这题真刺激...... I.关于Kruskal重构树,我只能开门了,不过补充一下那玩意还是一棵满二叉树.(看一下内容之前请先进门坐一坐) II.原来只是用树上倍增求Lca,但其实树上倍增是一种方法,Lca只是他的一种应用,他可以搞各种树上问题,树上倍增一般都会用到f数组. |||.我们跑出来dfs序就能在他的上面进行主席树了. IV.别忘了离散. V.他可能不连通,我一开始想到了,但是我觉得出题人可能会是好(S)人(B),但是...... #include <cstdio> #include

树上倍增 x

树上倍增. dfs序的做法: 思路: //f[i][j]表示dfs序中序号为i到序号为j的点之间深度最小的点的编号 dfs序[]//存0-...(id)编号 节点[]//存dfs序中所经过的节点号 dep[]//存走过的点所对应的点的深度 i : 1 2 3 4 5 6 7 ...... id[i] : (该点在节点编号中第一次出现的位置所对应的dfs序编号) //ans表示求u节点到i节点的最短距离... ans=f[id[u]][id[v]]; 至于代码……额……没写 树上倍增还能够用来求L

「Nescaf&#233;26」 Freda的传呼机 【树上倍增+图论】

题目: 为了随时与rainbow快速交流,Freda制造了两部传呼机.Freda和rainbow所在的地方有N座房屋.M条双向光缆.每条光缆连接两座房屋,传呼机发出的信号只能沿着光缆传递,并且传呼机的信号从光缆的其中一端传递到另一端需要花费t单位时间.现在Freda要进行Q次试验,每次选取两座房屋,并想知道传呼机的信号在这两座房屋之间传递至少需要多长时间.Freda和rainbow简直弱爆了有木有T_T,请你帮帮他们吧--N座房屋通过光缆一定是连通的,并且这M条光缆有以下三类连接情况:A:光缆不