您的位置:首页 > 其它

【模板】【LCA】【树上倍增】

2018-03-31 10:38 309 查看
题目索引:oi.nks.edu.cn/zh/Problem/Details/1536#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define DB double
#define SG string
#define LL long long
#define Fp(A,B,C,D) for(A=B;A<=C;A+=D)
#define Fm(A,B,C,D) for(A=B;A>=C;A-=D)
#define Clear(A) memset(A,0,sizeof(A))
using namespace std;
const LL Max=2e5+5;
const LL Mod=1e9+7;
const LL Inf=1e18;
LL N,M,Dis[Max],Deep[Max],Fa[Max][25];
//Dis[I]记录根节点到I号节点的距离,
//Deep[I]记录I号节点的深度
//Fa[X][K]表示X节点向上第2^K个祖先的编号
LL Cnt,To[Max],Edge[Max],Next[Max],Head[Max];
inline LL Read(){
LL X=0;char CH=getchar();bool F=0;
while(CH>'9'||CH<'0'){if(CH=='-')F=1;CH=getchar();}
while(CH>='0'&&CH<='9'){X=(X<<1)+(X<<3)+CH-'0';CH=getchar();}
return F?-X:X;
}
inline void Write(LL X){
if(X<0)X=-X,putchar('-');
if(X>9)Write(X/10);
putchar(X%10+48);
}
void Insert(LL X,LL Y,LL Z){
To[++Cnt]=Y;Edge[Cnt]=Z;Next[Cnt]=Head[X];Head[X]=Cnt;
}
void DFS(LL X,LL P,LL Q){//预处理Fa[][]数组//X为当前讨论的点,P为X的父亲节点,Q为X与P的连边边权
LL I,J,K;
Fa[X][0]=P; //记录父亲节点
Dis[X]=Dis[P]+Q;//记录距离
Deep[X]=Deep[P]+1;//记录深度
Fp(I,1,20,1){//倍增计算祖先
Fa[X][I]=Fa[Fa[X][I-1]][I-1];
}
for(I=Head[X];I;I=Next[I]){//递归讨论X的所有儿子
LL Y=To[I];
if(Y!=P){
DFS(Y,X,Edge[I]);
}
}
}
LL LCA(LL X,LL Y){//求X,Y的LCA编号
LL I,J,K,T;
if(Deep[X]<Deep[Y]){//保证Deep[X]<Deep[Y]方便计算
swap(X,Y);
}T=Deep[X]-Deep[Y];//求出X,Y两点的深度差
Fp(I,0,20,1){//X节点向上走T层
if(T&(1<<I)){
X=Fa[X][I];
}
}
if(X==Y){//如果此时X与Y相遇,则已得到X与Y的LCA
return Y;
}
Fm(I,20,0,1){//X,Y同时向上倍增
if(Fa[X][I]!=Fa[Y][I]){
X=Fa[X][I];
Y=Fa[Y][I];
}
}return Fa[X][0];
}
int main(){
LL I,J,K;
N=Read(),M=Read();
Fp(I,1,N-1,1){
LL X=Read(),Y=Read(),Z=Read();
Insert(X,Y,Z);
Insert(Y,X,Z);
}DFS(1,0,0);
Fp(I,1,M,1){
LL X=Read(),Y=Read();
Write(Dis[X]+Dis[Y]-(Dis[LCA(X,Y)]<<1));puts("");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: