• [HDU--2586] How far away ? 倍增LCA


    Problem Description

    There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this “How far is it if I want to go from house A to house B”? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path(“simple” means you can’t visit a place twice) between every two houses. Yout task is to answer all these curious people.

    Input

    First line is a single integer T(T<=10), indicating the number of test cases.
    For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0<k<=40000).The houses are labeled from 1 to n.
    Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.

    Output

    For each test case,output m lines. Each line represents the answer of the query. Output a bland line after each test case.

    Sample Input

    2
    3 2
    1 2 10
    3 1 15
    1 2
    2 3

    2 2
    1 2 100
    1 2
    2 1

    Sample Output

    10
    25
    100
    100

    题目大意:给一个无根树,有q个询问,每个询问两个点,问两点的距离。
    思路 : 应该是LCA的裸题,因为是树求一下最近公共祖节点,然后记录一下路径长度就行了,但是因为是无根树,所以需要选一个点作为根节点,我选 1 号节点

    AC code:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <cmath>
    
    using namespace std;
    
    const int maxn = 4e4+50;
    const int logtwo = 30;
    
    struct edge{
    	int to ,w ;
    	edge(){}
    	edge(int _w,int _to){ w = _w; to = _to; }
    };
    
    vector<edge>G[maxn];
    int grand[maxn][logtwo],depth[maxn],gw[maxn][logtwo];
    int n,m,N;
    
    void dfs(int x) {
    	for (int i = 1;i <= N ; i ++) {
    		grand[x][i] = grand[grand[x][i-1]][i-1];
    		gw[x][i] = gw[grand[x][i-1]][i-1] + gw[x][i-1];
    	}
    	int len = G[x].size();
    	for (int i = 0;i < len ; i ++ ) {
    		edge e = G[x][i];
    		if ( grand[x][0] != e.to ) {
    			depth[e.to] = depth[x] + 1 ;
    			grand[e.to][0] = x; gw[e.to][0] = e.w;
    			dfs(e.to);
    		}
    	}
    }
    
    void init() {
    	N = floor( log(n + 0.0) / log(2.0) );
    	memset(depth,0,sizeof(depth));
    	memset(grand,0,sizeof(grand));
    	memset(gw,0,sizeof(gw));
    	dfs(1);
    }
    
    int lca(int a,int b) {
    	if ( depth[a] > depth[b] ) swap(a,b);
    	int ans = 0;
    	for (int i = N;i >= 0;i--) {
    		if ( depth[a] < depth[b] && depth[grand[b][i]] >= depth[a] )
    			ans += gw[b][i] , b = grand[b][i];
    	} 
    	for (int j = N; j >= 0 ; j -- ) {
    		if ( grand[a][j] != grand[b][j]  ) {
    			ans += gw[a][j]; ans += gw[b][j];
    			a = grand[a][j]; b = grand[b][j];
    		}
    	}
    	if(a != b) ans += gw[a][0], ans += gw[b][0];
    	return ans;
    }
    
    int main(){
    	int t; cin>>t;
    	while ( t -- ) {
    		scanf("%d %d",&n,&m);
    		for (int i = 0;i <= n;i++) G[i].clear();
    		int u,v,w;
    		for ( int i = 0; i < n-1 ; i ++ ) {
    			scanf("%d %d %d",&u,&v,&w);
    			G[u].push_back(edge(w,v));
    			G[v].push_back(edge(w,u));
    		}
    		init();  int a ,b ;
    		for (int i = 1;i <= m; i ++ ) {
    			scanf("%d %d",&a,&b);
    			printf("%d
    ",lca(a,b));
    		}
    	}	
    	return 0;
    }
    

    补充后来又学了一种板子感觉比以前的好用

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 4e4 + 50 ;
    const int logtwo = 30 ;
    
    struct edge {
    	int nxt ,w ,to ;
    }ss[maxn << 2];
    
    int head[maxn] ,depth[maxn] ,father[maxn][logtwo] ,fw[maxn] ;
    int n ,m ,cnt ,u ,v ,w ,s1 ,s2 ;
    
    void init() {
    	cnt = 0;
    	memset(depth ,0 ,sizeof(depth)) ;
    	memset(fw ,0 ,sizeof(fw)) ;
    	memset(father ,0 ,sizeof(father)) ;
    	memset(head ,-1 ,sizeof(head)) ;
    }
    
    void _add(int u,int v,int w) {
    	ss[++cnt].w = w;
    	ss[cnt].to = v;
    	ss[cnt].nxt = head[u];
    	head[u] = cnt ;
    }
    
    void add_edge(int u,int v,int w) {
    	_add(u ,v ,w) ;
    	_add(v ,u ,w ) ;
    }
    
    void dfs(int x) {
    	for (int i = 1 ; (1 << i) <= depth[x] ; i ++ ) {
    		father[x][i] = father[father[x][i-1]][i-1];
    	}
    	for (int i = head[x] ; ~i ; i = ss[i].nxt ) {
    		int v = ss[i].to ;
    		if ( v != father[x][0] ) {
    			father[v][0] = x;
    			depth[v] = depth[x] + 1;
    			fw[v] = fw[x] + ss[i].w ;
    			dfs(v ) ;
    		}
    	}
    }
    
    int lca(int a,int b) {
    	if ( depth[a] > depth[b] ) swap(a ,b ) ;
    	int dis = depth[b] - depth[a] ;
    	for (int i = 0 ; (1<<i) <= dis ; i ++ ) {
    		if ( dis & ( 1 << i) ) {
    			b = father[b][i];
    		}
    	}
    	if ( a == b ) return a;
    	for (int i = 29 ; i >= 0 ; i -- ) {
    		if ( father[a][i] != father[b][i] ) {
    			a = father[a][i];
    			b = father[b][i];
    		}
    	}
    	return father[a][0];
    }
    
    int main() {
    	int t; cin >> t ;
    	while( t -- ) {
    		init() ;
    		scanf("%d %d",&n,&m);
    		for (int i = 1 ; i < n  ; i ++ ) {
    			scanf("%d %d %d",&u ,&v ,&w ) ;
    			add_edge(u ,v ,w );
    		}
    		dfs(1) ;
    		for (int i = 1 ; i <= m ; i ++ ) {
    			scanf("%d %d",&s1 ,&s2 ) ;
    			printf("%d
    ",fw[s1] + fw[s2] - 2 * fw[lca(s1 ,s2 )] );
    		} 
    	}
    	return 0;
    }
    
  • 相关阅读:
    sqlServer的主键只能自增不能手动增加
    TP函数
    TP复习17
    TP复习16
    TP复习15
    TP复习14
    TP复习13
    TP复习12
    TP复习11
    TP复习10
  • 原文地址:https://www.cnblogs.com/Nlifea/p/11745952.html
Copyright © 2020-2023  润新知