【codevs2370】小机房的树

输入描述 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 
#include 

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< 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<=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


你可能感兴趣的:(LCA)