hdu2586 How far away ?
题意:
给一棵n个节点的树,n-1条带权的边,m个询问,每次询问给出a,b,输出a到b的最短距离
保证1为根
分析:
LCA模板
有的题目要判断连通性
有的题目要自己找根(入度为0的是根)
倍增(bfs):
倍增的时候最好令dep[0]和dep[root]不同
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<cmath>
#include<algorithm>
typedef long long ll;
using namespace std;
const int maxm=4e4+5;
int head[maxm],nt[maxm<<1],to[maxm<<1],w[maxm<<1],cnt;
int f[maxm][20],d[maxm],dist[maxm];
int n,m;
int maxd;//最大层数
void init(){
memset(head,-1,sizeof head);
cnt=1;
maxd=log(n)/log(2)+1;
}
void add(int x,int y,int z){
cnt++;nt[cnt]=head[x];head[x]=cnt;to[cnt]=y;w[cnt]=z;
}
void bfs(int st){
queue<int>q;
q.push(st);
memset(d,0,sizeof d);
d[st]=1;
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=head[x];i!=-1;i=nt[i]){
int v=to[i];
if(!d[v]){
d[v]=d[x]+1;
dist[v]=dist[x]+w[i];
q.push(v);
f[v][0]=x;
for(int j=1;j<=maxd;j++){
f[v][j]=f[f[v][j-1]][j-1];
}
}
}
}
}
int lca(int a,int b){
if(d[a]<d[b])swap(a,b);//把a定为更深的
for(int i=maxd;i>=0;i--){//爬到同一高度
if(d[f[a][i]]>=d[b]){
a=f[a][i];
}
}
if(a==b)return a;
for(int i=maxd;i>=0;i--){
if(f[a][i]!=f[b][i]){
a=f[a][i];
b=f[b][i];
}
}
return f[a][0];
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
init();
for(int i=1;i<=n-1;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
add(b,a,c);
}
bfs(1);
for(int i=1;i<=m;i++){
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",dist[a]+dist[b]-2*dist[lca(a,b)]);
}
}
return 0;
}
倍增(dfs):
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxm=4e4+5;
int head[maxm],nt[maxm<<1],to[maxm<<1],w[maxm<<1],cnt;
int f[maxm][20],d[maxm],dist[maxm];
int n,m;
int maxd;//最大层数
void init(){
memset(head,-1,sizeof head);
cnt=1;
maxd=log(n)/log(2)+1;
}
void add(int x,int y,int z){
cnt++;nt[cnt]=head[x];head[x]=cnt;to[cnt]=y;w[cnt]=z;
}
void dfs(int x,int dep,int val){
d[x]=dep;
for(int i=head[x];i!=-1;i=nt[i]){
int v=to[i];
if(!d[v]){
f[v][0]=x;
dist[v]=val+w[i];
dfs(v,dep+1,val+w[i]);
}
}
}
int lca(int a,int b){
if(d[a]<d[b])swap(a,b);//把a定为更深的
for(int i=maxd;i>=0;i--){//爬到同一高度
if(d[f[a][i]]>=d[b]){
a=f[a][i];
}
}
if(a==b)return a;
for(int i=maxd;i>=0;i--){
if(f[a][i]!=f[b][i]){
a=f[a][i];
b=f[b][i];
}
}
return f[a][0];
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
init();
for(int i=1;i<=n-1;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
add(b,a,c);
}
memset(d,0,sizeof d);//清空d
dfs(1,1,0);
f[1][0]=1;
for(int j=1;j<=maxd;j++){
for(int i=1;i<=n;i++){
f[i][j]=f[f[i][j-1]][j-1];
}
}
for(int i=1;i<=m;i++){
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",dist[a]+dist[b]-2*dist[lca(a,b)]);
}
}
return 0;
}
离线tarjan
年代久远,已经忘了,有空补
树剖
树剖就不放代码了