zoukankan      html  css  js  c++  java
  • GalaxyOJ-468 (LCA)

    题目

    Problem Description

    穷游中国队又去游中国了。
    穷游中国队去到了一个城市,这个城市有n个区,n-1条路,每条路连接不同的两个区,而且每两个区有且仅有一条路径,每条路上都有一个收费站,如果经过这条路就要收取一定的费用。
    现在穷游中国队在编号为a的区住了一个晚上,第二天打算去编号为b的区,问路费一共要花多少钱?(在一个区里面行走不用收费)

    Input

    第一行两个数n和q,表示区的个数和询问个数
    接下来有n-1行,每行三个数i,j,k,表示第i个区到第j个区有一条路,且要收费k元
    接下来有q行,每行两个数,分别是a和b
    $ 2<=n<=40000 1<=m<=200 0<k<=40000$

    Output

    对于每个询问,输出一个整数,表示从a区走到b区要花多少钱。

    Sample Input

    |#|Input|Output|
    |-|-|-|
    |1|3 2
    1 2 10
    3 1 15
    1 2
    2 3
    |10
    25|
    |2|2 2
    1 2 100
    1 2
    2 1|100
    100|

    分析

    • 从数据范围来看,直接搜索是没前途的,注意到边比点少一个,而且点与点之间没有重复的边,于是这就变成了一棵树,所以,我们想到了LCA。
    • 首先随便dfs一下给这棵树的节点编个顺序。
    • 不难看出,对于这个要从一个点到另一个点,是一定要经过他们的最近公共祖先的,而且路径就是从这个点到它们的公共祖先,然后再走下去到另一个点,于是就是一个近乎模板的题了。
    • 具体操作与LCA几乎相同,用求fa[][]相似的方法求出val[i][x](节点i跳到 (2^x) 代祖先所需的路费),对于每个询问只需加一下对应的路费就行了。

    程序

    第一次打LCA,程序有点丑……

    #include <cstdio>
    #define For(x) for (int o=head[x],k=nn[o]; o; o=To[o],k=nn[o])
    int A,B,n,q,num,w[80010],head[40010],nn[80010],val[80010][25],To[80010],f[40010],d[40010],fa[40010][25];
    void add(){
    	int u,v,ww; scanf("%d%d%d",&u,&v,&ww);
    	To[++num]=head[u], head[u]=num, nn[num]=v, w[num]=ww;
    	To[++num]=head[v], head[v]=num, nn[num]=u, w[num]=ww;
    }
    void dfs(int x,int dep){
    	d[x]=f[x]=dep;
    	For(x) if (!f[k]){
    		fa[k][0]=x;
    		val[k][0]=w[o];
    		dfs(k,dep+1);
    	}
    }
    void Get_fa(){
    	for (int j=1; j<=20; j++) for (int i=1; i<=n; i++){
    		fa[i][j]=fa[fa[i][j-1]][j-1];
    		val[i][j]=val[fa[i][j-1]][j-1]+val[i][j-1];
    	}
    }
    
    int F(int x,int y){	//xµÄµÚy´ú׿ÏÈ 
    	for (int i=0; y; i++){
    		if (y&1) x=fa[x][i];
    		y>>=1;
    	}
    	return x;
    }
    
    int V(int x,int y){	//xµ½µÚy´ú׿ÏȵÄÖµ 
    	int ans=0;
    	for (int i=0; y; i++) {
    		if (y&1) ans+=val[x][i],x=fa[x][i];
    		y>>=1;
    	}
    	return ans;
    }
    
    int LCA(int x,int y){
    	for (int i=20; i>=0; i--) if (d[x]-1>=1<<i)
    		if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    	return fa[x][0];
    }
    
    int main(){
    	scanf("%d%d",&n,&q);
    	for (int i=1; i<n; i++) add();
    	fa[1][0]=1; dfs(1,1);
    	Get_fa();	
    	while (q--){
    		int Sum=0;
    		scanf("%d%d",&A,&B);
    		if (d[A]>d[B]) Sum+=V(A,d[A]-d[B]),A=F(A,d[A]-d[B]);
    		if (d[B]>d[A]) Sum+=V(B,d[B]-d[A]),B=F(B,d[B]-d[A]);
    		int kk;
    		if (A!=B){
    			kk=LCA(A,B);
    			Sum+=V(A,d[A]-d[kk])+V(B,d[B]-d[kk]);
    		}
    		printf("%d
    ",Sum);
    	}
    	//for (int i=1; i<=n; i++) printf("[%d]	%d	%d
    ",i,d[i],fa[i][0]);
    }
    
  • 相关阅读:
    数据泵使用笔记与相关shell
    手动创建数据库
    归档日志小试
    SQL语句的结果如何反映在SGA与磁盘中
    oracle 表空间
    linux 循环判断、数组、循环
    oracle 连接方式
    Changing Project Binding to Surround SCM Integration Provider with Visual Studio 2010
    On Caching and Evangelizing SQL
    Windows下使用python3 + selenium实现网页自动填表功能
  • 原文地址:https://www.cnblogs.com/hehepig/p/6685705.html
Copyright © 2011-2022 走看看