首页 > 代码库 > 【codevs】2370 小机房的树

【codevs】2370 小机房的树

 时间限制: 1 s

 空间限制: 256000 KB

 

题目描述 Description

小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上。有一天,他们想爬到一个节点上去搞基,但是作为两只虫子,他们不想花费太多精力。已知从某个节点爬到其父亲节点要花费 c 的能量(从父亲节点爬到此节点也相同),他们想找出一条花费精力最短的路,以使得搞基的时候精力旺盛,他们找到你要你设计一个程序来找到这条路,要求你告诉他们最少需要花费多少精力

输入描述 Input Description

第一行一个n,接下来n-1行每一行有三个整数u,v, c 。表示节点 u 爬到节点 v 需要花费 c 的精力。

第n+1行有一个整数m表示有m次询问。接下来m行每一行有两个整数 u ,v 表示两只虫子所在的节点。

输出描述 Output Description

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

样例输入 Sample Input

3

1 0 1

2 0 1

3

1 0

2 0

1 2

样例输出 Sample Output

1

1

2

 

数据范围及提示 Data Size & Hint

1<=n<=50000, 1<=m<=75000, 0<=c<=1000

 

技术分享
 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int maxn=50010;
 5 struct point{int from,to,v;}e[maxn*2];
 6 int n,m,cnt,a,b,c;
 7 int head[maxn],deep[maxn],x[maxn][17],di[maxn];
 8 //deep数组表示节点所在的层数,di数组表示节点到根节点的距离 
 9 //x[i][j]的含义为:节点i的祖先中与其相差2^j层的节点;例如,x[i][0]代表节点i的父亲 
10 bool f[maxn];//判断节点是否访问过 
11 void add(int a,int b,int c)//邻接表建边 
12 {cnt++;e[cnt].from=head[a];e[cnt].to=b;e[cnt].v=c;head[a]=cnt;}
13 void dfs(int k)
14 {
15     f[k]=true;
16     for(int i=1;(1<<i)<=deep[k];i++)
17         x[k][i]=x[x[k][i-1]][i-1];//递推得出x数组 
18     for(int i=head[k];i;i=e[i].from) 
19     {
20         if(!f[e[i].to])
21         {
22             x[e[i].to][0]=k;//将节点k标记为e[i].to的父亲 
23             deep[e[i].to]=deep[k]+1;//层数+1 
24             di[e[i].to]=di[k]+e[i].v;
25             dfs(e[i].to);
26         }
27     }
28 }
29 int solve(int ri,int rj)
30 {
31     if(deep[ri]<deep[rj])swap(ri,rj);
32     int d=deep[ri]-deep[rj]; 
33     for(int i=0;(1<<i)<=d;i++)//利用倍增思想,将ri节点跳到与rj节点同层 
34         if((1<<i)&d)ri=x[ri][i];
35     if(ri==rj)return ri;//找到最近公共祖先 
36     for(int i=16;i>=0;i--)
37         if((1<<i)<=deep[rj]&&x[ri][i]!=x[rj][i])
38             ri=x[ri][i],rj=x[rj][i];//同时往上跳,直到ri与rj为兄弟节点为止 
39     return x[ri][0];//返回他们的父亲 
40 }
41 int main()
42 {
43     scanf("%d",&n);
44     for(int i=1;i<n;i++)
45     {
46         scanf("%d%d%d",&a,&b,&c);
47         add(a,b,c);
48         add(b,a,c);
49     }
50     dfs(0);//此处假设以0为根节点 
51     scanf("%d",&m);
52     while(m--)
53     {
54         scanf("%d%d",&a,&b);
55         printf("%d\n",di[a]+di[b]-2*di[solve(a,b)]);
56     }
57     return 0;
58 }
View Code

 

【codevs】2370 小机房的树