lca板子

#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int M=500010;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<‘0‘||c>‘9‘){if(c==‘-‘) f=-1; c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){ans=ans*10+(c-‘0‘); c=getchar();}
    return ans*f;
}
int n,q,k;
LL ans,dis[M];
LL f[M][35],vis[M],deep[M];
LL first[M],cnt;
struct node{LL to,next,w;}e[M];
void ins(LL a,LL b,LL w){e[++cnt]=(node){b,first[a],w}; first[a]=cnt;}
void insert(LL a,LL b,LL w){ins(a,b,w); ins(b,a,w);}
void dfs(LL x){
    vis[x]=1;
    for(int i=1;(1<<i)<=deep[x];i++) f[x][i]=f[f[x][i-1]][i-1];
    for(int i=first[x];i;i=e[i].next){
        int now=e[i].to;
        if(!vis[now]){
            deep[now]=deep[x]+1;
            f[now][0]=x;
            dis[now]=dis[x]+e[i].w;
            dfs(now);
        }
    }
}
int find(int x,int y){
    if(deep[x]<deep[y]) swap(x,y);
    int d=deep[x]-deep[y];
    for(int i=0;(1<<i)<=d;i++) if((1<<i)&d) x=f[x][i];
    if(x==y) return x;
    for(int i=30;i>=0;i--)
     if((1<<i)<=deep[x]&&f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}
int main(){
    int x,y,w;
    n=read();
    for(int i=1;i<n;i++) x=read(),y=read(),w=read(),insert(x,y,w);
    dfs(1);
    q=read(); k=read();
    for(int i=1;i<=q;i++){
        x=read(); y=read();
        ans=0;
        int s1=find(x,k),s2=find(y,k);
        LL sum1=dis[x]+dis[k]-dis[s1]*2;
        LL sum2=dis[y]+dis[k]-dis[s2]*2;
        ans=ans+sum1+sum2;
        printf("%lld\n",ans);
    }
    return 0;
}

时间: 2024-10-28 10:06:56

lca板子的相关文章

求最近公共祖先(LCA)板子 x

LCA目前比较流行的算法主要有tarjian,倍增和树链剖分 1)tarjian 是一种离线算法,需要提前知道所有询问对 算法如下 1.读入所有询问对(u,v),并建好树(建议邻接表) 2.初始化每个节点各属一个并查集,都指向自己 3.对整棵树进行dfs(深度优先搜索)遍历 每处理到一个新节点(u)时看他的另一半(询问对象v)是否visit过,如果visit过了,则这组询问对的lca即v的并查集的根节点,若没有visit过,则继续向下深搜,该节点记为已visit 每当回溯的时候都将子节点的并查集

SPOJ COT Count on a tree(树上主席树 + LCA 求路径第k小)题解

题意:n个点的树,每个点有权值,问你u~v路径第k小的点的权值是? 思路: 树上主席树就是每个点建一棵权值线段树,具体看JQ博客,LCA用倍增logn求出,具体原理看这里 树上主席树我每个点的存的是点u到源点1的权值线段树,那我求点u到v的所有点,显然是 u + v - lca - fa[lca],就是u到1 + v到1 - 多算的lca - 多算的fa[lca].不能减去两个lca不然少一个点了, LCA板子: //LCA int fa[maxn][20]; int dep[maxn]; vo

[Codeforces#519E] A and B and Lecture Rooms

Codeforces题号:#519E 出处: Codeforces 主要算法:最近公共祖先LCA(倍增法) 难度:4.5 思路分析: 题意:询问给出一棵无根树上任意两点a,b,求关于所有点i,\(dist(a,i) = dist(b,i)\)的点的数量.要求每一次询问在O(log n)的时间复杂度内完成. 由于在树上求距离,并且还要O(log n),自然会联想到LCA.由于边权是1,那么点到根的距离就是该点的深度.这个深度可以在dfs预处理的过程中处理完成.那么两个点之间的距离就是两个点到根节点

CSUST选拔赛题解

---恢复内容开始--- A:哭泣的阿木木 题目链接:http://csustacm.com:4803/contest/26/problem/J 思路:这是一个很裸的线段树+lazy数组标记,直接用板子就可以了,数据很大很多,所以开long long,并且用scanf,printf输入输出. 代码如下: 1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cmat

Nearest Common Ancestor

POJ上的题,其实就是LCA板子.先预处理每个点倍增祖先,然后每组询问先使x和y达到同一深度,然后一起往上跳到公共祖先的+1深度的点. die码: #include<cstdio> #include<algorithm> #define maxn 500010 using namespace std; int head[maxn],nxt[maxn<<1],to[maxn<<1],cnt; int deep[maxn],f[maxn][21]; inline

考后反思(bzoj3940 bzoj4899 bzoj3307)

考试的时候用哈希水过了第一题本来想用哈希只可以得20左右没想到由于数据过于水A了 然后雨天的尾巴骗了5分,总分105 我太菜了 首先时间分配的不合理:第一题大水题ac自动机打完了都不会,第二题略微想了想打了个高斯消元,然后样例没过......,最后输出了一个随机数,第三题(lca板子忘了,打错一个地方,没有调出来)最后骗了五分 考后主要讲一下第二题:记忆的轮廓(bzoj4899)和第三题:雨天的尾(yi)巴(bzoj3307) Censoring FJ把杂志上所有的文章摘抄了下来并把它变成了一个

考试心得 模拟12

先干的T2  1个小时,啥都没打出来, 想到了线段树,分块,莫队,都能骗到不少分,但我都没想到怎么实现 其中有20分钟浪费在了没打完的线段树上,想好了再打,别浪费时间 T1 自己努力够到的天花板,只是别人的起跑线 找了10分钟规律,找到了父节点与儿子节点的关系,然后用手去打表,想要卡常,但你能不能先想到严密的思路再去用手码 又浪费了10分钟去摸索打表,然后发现没用,心思在打表卡常上卡了好久, 发现只能暴力建树,还有一个半小时结束考试,开始打,坑坑迟迟,lca板子不熟练,没信心 比往常数组多开成2

xsy 2414【CF587C】Duff in the Army

Description [题目描述]: 最近有一场战争发生,Duff是战争里一名士兵,Malek是她的长官. 他们的国家——Andarz Gu有n个城市(编号为1到n),总共有n-1条道路,每条道路连接着不同的两个城市,保证两两城市间必定可以通过道路到达. Andarz Gu总共有m个人,每个人分别对应着编号1到m,对于第i个人,我们可以知道他还有一个编号ci,表示这个编号为i的人住在编号为ci的城市.注意一个城市里可能有不止一个人,也可能没有人住在这个城市. Malek喜欢下达指令,这也是她要

板子——LCA

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