【模板】【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;
}
#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;
}
相关文章推荐
- 模板 树上求LCA 倍增和树链剖分
- 树上倍增求LCA(最近公共祖先)
- 树上倍增求LCA
- 【BZOJ-4281】Związek Harcerstwa Bajtockiego 树上倍增LCA
- LCA树上倍增
- 倍增LCA模板
- 【 lca倍增模板】
- 【NOIP2016提高组T2】天天爱跑步-倍增LCA+树上差分
- 倍增求lca(模板)
- hdu2586 倍增lca模板
- 关于树上倍增求LCA
- 倍增lca模板
- 倍增求LCA的模板
- 【模板】倍增LCA [2017年5月计划 清北学堂51精英班 Day3]
- [bzoj3123][洛谷P3302] [SDOI2013]森林(树上主席树+倍增lca+启发式合并)
- [置顶] 对LCA、树上倍增、树链剖分(重链剖分&长链剖分)和LCT(Link-Cut Tree)的学习(填坑ing)
- bzoj3732 Network 最小生成树+LCA+树上倍增
- 【讲解+模板】最近公共祖先(LCA)(倍增)
- [模板] - LCA倍增
- 最近公共祖先(LCA)之树上倍增法