【codevs2370】小机房的树

来源:互联网 发布:主机域名哪个是主机名 编辑:程序博客网 时间:2024/05/18 03:03
输入描述 Input Description
第一行一个n,接下来n-1行每一行有三个整数u,v, c 。表示节点 u 爬到节点 v 需要花费 c 的精力。
第n+1行有一个整数m表示有m次询问。接下来m行每一行有两个整数 u ,v 表示两只虫子所在的节点
输出描述 Output Description

一共有m行,每一行一个整数,表示对于该次询问所得出的最短距离。

 算法:倍增LCA。

大致思路:建边时双向建,值得注意的是根结点要自己选择,这里选择的是0。用grand【i】【j】表示i结点2^j处的祖先,dis【i】【j】表示它与祖先的距离。然后跳时注意dis的改变方式。

几点提醒:LCA一定要记住
1.双向边,开结构体时maxx要左推一位。
2.20到0是i--,不是++。
3.grand数组,如果要play20,数组至少第二维开21,最好到22。
4.一定一定要先dfs root结点。


↑都是语言没学好的锅 = =


代码:

#include <cstdio>#include <algorithm>using namespace std;const int maxx = 50000 + 100;int head[maxx],depth[maxx];int grand[maxx][20+2],dis[maxx][20+2];bool done[maxx];int n,m,x,y,z,num,root;struct Edge{    int next;    int to;    int value;}Edges[maxx<<1];inline int Read(){    int x=0,f=1;char c=getchar();    while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}    while(c>='0'&&c<='9') {x=x*10+c-'0'; c=getchar();}    return x*f;}void Add(int x,int y,int z){    Edges[++num].to=y;    Edges[num].next=head[x];    Edges[num].value=z;    head[x]=num;}void Dfs(int x){    done[x]=true;    for(int i=1;i<=20;i++){if((1<<i) > depth[x]) break;grand[x][i]=grand[grand[x][i-1]][i-1];dis[x][i]=dis[x][i-1]+dis[grand[x][i-1]][i-1];    }    for(int i=head[x];i;i=Edges[i].next){int now=Edges[i].to;if(done[now]) continue;depth[now]=depth[x]+1;grand[now][0]=x;dis[now][0]=Edges[i].value;Dfs(now);    }}inline int Lca(int x,int y){    int Ans=0;    if(depth[x]>depth[y]) swap(x,y);    int d=depth[y]-depth[x];    for(int i=0;i<=20;i++){if((1<<i) & d) {    Ans += dis[y][i];    y=grand[y][i];}    }    for(int i=20;i>=0;i--){if(grand[x][i]!=grand[y][i]){    Ans += dis[x][i];    Ans += dis[y][i];    x=grand[x][i];    y=grand[y][i];}    }    if(x==y) return Ans;    else{Ans+=dis[x][0]+dis[y][0];return Ans;    }}int main(){    n=Read();    for(int i=1;i<n;i++){x=Read();y=Read();z=Read();Add(x,y,z);Add(y,x,z);    }    Dfs(0);    m=Read();    while( m-- ){x=Read();y=Read();printf("%d\n",Lca(x,y));    }    return 0;}


0 0