题目大意:
给出n个点m条边,输入m行每行3个数字,1个字母,分别是边的端点和权值,字母么??打酱油的…然后k个询问,询问树上x~y的路径长度
Attention!!please!!
n<=10W不是4W,WA了好多遍O(≧口≦)O
分析:
这妥妥のLCA…
在线算法……
倍增法求LCA…..
很好理解,不再解释,直接上代码….
代码如下:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=100000+5;
int n,m,k,cnt,hd[maxn],to[maxn*2],nxt[maxn*2],w[maxn],fa[maxn][35],dep[maxn],dis[maxn];
char djyd[10];
inline void add(int x,int y,int s){
w[cnt]=s;
to[cnt]=y;
nxt[cnt]=hd[x];
hd[x]=cnt++;
}
inline void init(){
for(int j=1;j<=30;j++)
for(int i=1;i<=n;i++)
fa[i][j]=fa[fa[i][j-1]][j-1];
}
inline void dfs(int root,int f){
for(int i=hd[root];i!=-1;i=nxt[i])
if(to[i]!=f)
fa[to[i]][0]=root,dis[to[i]]=dis[root]+w[i],dep[to[i]]=dep[root]+1,dfs(to[i],root);
}
inline int LCA(int a,int b){
if(dep[a]<dep[b])
swap(a,b);
int d=dep[a]-dep[b];
for(int i=0;i<=30;i++)
if((1<<i)&d)
a=fa[a][i];
if(a==b)
return b;
for(int i=30;i>=0;i--)
if(fa[a][i]!=fa[b][i])
a=fa[a][i],b=fa[b][i];
return fa[a][0];
}
signed main(void){
while(scanf("%d%d",&n,&m)!=EOF){
cnt=0,memset(hd,-1,sizeof(hd));
for(int i=1,x,y,z;i<=m;i++)
scanf("%d%d%d%s",&x,&y,&z,djyd),add(x,y,z),add(y,x,z);
fa[1][0]=1,dep[1]=dis[1]=0,dfs(1,-1),init(),scanf("%d",&k);
for(int i=1,x,y;i<=k;i++)
scanf("%d%d",&x,&y),cout<<dis[x]+dis[y]-2*dis[LCA(x,y)]<<endl;
}
return 0;
}
by >_< neighthorn