Code[VS] 2370 LCA 题解

Code[VS] 2370 小机房的树 题解

LCA

题目描述 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

———————————————————————————分割线—————————————————————————————

分析:

这道题是一个比较明显的求树上路径的题,显然

Ans = dis[ u ] + dis[v] - 2*dis[ LCA( u , v ) ]   

所以本题核心是求LCA ,将LCA问题转化为RMQ问题。这里使用线段树查询解决。

代码&注释:

  1 /*
  2     LCA
  3     author:SHHHS
  4     2016-09-26 02:25:19
  5 */
  6
  7 #include "bits/stdc++.h"
  8
  9 using namespace std ;
 10 typedef long long QAQ ;
 11 struct Edge { int to , val , next ;};
 12 struct Tree { int l , r , mintr ,pos ;};
 13 int gmin ( int x , int y ) { return x > y ? y : x ;}
 14 int gmax ( int x , int y ) { return x < y ? y : x ;}
 15 const int maxN = 200010 ;
 16 const int INF = 2147483647 ;
 17
 18 Tree tr[ maxN<<2 ] ;
 19 Edge e[ maxN ] ;
 20 int cnt , dfs_num=0 , min_val ,min_pos ;
 21 int head[maxN],fst[maxN],dep[maxN],ver[maxN],Dis[maxN];
 22 bool vis[maxN];
 23
 24 inline void Add_Edge ( int x , int y , int _val ){
 25          e[ ++cnt ].to = y ;
 26          e[ cnt ].val = _val ;
 27          e[ cnt ].next = head[ x ] ;
 28          head[ x ] = cnt ;
 29 }
 30
 31 void Build_Tree ( int x , int y , int i ) {
 32          tr[ i ].l = x ; tr[ i ].r = y ;
 33          if ( x==y ) tr[ i ].mintr = dep[ x ] , tr[ i ].pos = x ;
 34          else {
 35                   QAQ mid = ( tr[ i ].l + tr[ i ].r ) >>1 ;
 36                  Build_Tree ( x , mid , i<<1);
 37                  Build_Tree ( mid+1 , y , i<<1|1);
 38                  if (tr[i<<1].mintr > tr[i<<1|1].mintr )
 39                           tr[ i ].pos = tr[i<<1|1].pos,tr[ i ].mintr = tr[i<<1|1].mintr;
 40                  else
 41                          tr[ i ].pos = tr[ i<<1 ].pos,tr[ i ].mintr = tr[ i<<1 ].mintr;
 42          }
 43
 44 }
 45
 46 void DFS ( int x , int depth ) {
 47          vis[ x ] = true ;
 48          ver[ ++dfs_num ] = x ;
 49          fst[ x ] = dfs_num ;
 50          dep[ dfs_num ] = depth ;
 51          for ( int i=head[ x ] ; i ; i=e[i].next ) {
 52                   int temp = e[ i ].to ;
 53                   if ( !vis[ temp ] ){
 54                            Dis[ temp ] = Dis[ x ] + e[ i ].val ;
 55                            DFS ( temp , depth + 1 ) ;
 56                            ver[ ++dfs_num ] = x ;
 57                            dep[ dfs_num ] = depth ;
 58                  }
 59          }
 60 }
 61
 62 void Query_Min ( int q , int w , int i ) {
 63          if(q <= tr[i].l && w >= tr[i].r ){
 64                   if (tr[ i ].mintr < min_val ){
 65                            min_val = tr[i].mintr ;
 66                            min_pos = tr[i].pos ;
 67                   }
 68          }
 69          else {
 70                   QAQ mid = (tr[i].l + tr[i].r ) >> 1;
 71                   if(q > mid) {
 72                           Query_Min ( q , w , i << 1 | 1);
 73                   }
 74                   else if(w <= mid) {
 75                           Query_Min ( q , w , i << 1);
 76                   }
 77                   else {
 78                           Query_Min ( q , w , i << 1) ;
 79                           Query_Min ( q , w , i << 1 | 1);
 80                   }
 81          }
 82 }
 83
 84 int LCA ( int x , int y ) {
 85          int px = fst[ x ] , py = fst[ y ] , tmp ;
 86          min_val = INF ;
 87          if ( py < px ) swap ( px , py ) ;
 88          Query_Min ( px , py , 1 ) ;
 89          return ver[ min_pos ] ;
 90 }
 91 int main ( ) {
 92          int N ,M ;
 93          scanf ("%d",&N);
 94          for ( int i=1 ; i<=N-1 ; ++i ) {
 95                   int _x , _y , __ ;
 96                   scanf("%d %d %d" , &_x , &_y ,&__ ) ;
 97                   ++_x;++_y;
 98                   Add_Edge ( _x , _y , __ ) ;
 99                   Add_Edge ( _y , _x , __ ) ;
100          }
101          DFS ( 1 , 1 ) ;
102          Build_Tree ( 1 , dfs_num , 1 ) ;
103          scanf ("%d",&M);
104          for ( int i=1 ; i<=M ; ++i ) {
105                   int u , v ;
106                   scanf ( "%d%d" , &u , &v ) ;
107                   ++u,++v;
108                   printf ("%d",Dis[u]+Dis[v]-2*Dis[LCA ( u , v )] ) ;
109                   putchar(‘\n‘);
110          }
111          return 0 ;
112 }

02:23:34 2016-09-26

(完)

时间: 2024-08-05 23:32:10

Code[VS] 2370 LCA 题解的相关文章

POJ 1330 Nearest Common Ancestors LCA题解

本题是一个多叉树,然后求两点的最近公共单亲节点. 就是典型的LCA问题.这是一个很多解法的,而且被研究的很透彻的问题. 原始的解法:从根节点往下搜索,若果搜索到两个节点分别在一个节点的两边,那么这个点就是最近公共单亲节点了. Trajan离线算法:首次找到两个节点的时候,如果记录了他们的最低单亲节点,那么答案就是这个最低的单亲节点了. 问题是如何有效记录这个最低单亲节点,并有效根据遍历的情况更新,这就是利用Union Find(并查集)记录已经找到的节点,并及时更新最新访问的节点的当前最低单亲节

Code[VS]1690 开关灯 题解

Code[VS]1690 开关灯 题解  时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description: YYX家门前的街上有N(2<=N<=100000)盏路灯,在晚上六点之前,这些路灯全是关着的,六点之后,会有M(2<=m<=100000)个人陆续按下开关,这些开关可以改变从第i盏灯到第j盏灯的状态,现在YYX想知道,从第x盏灯到第y盏灯中有多少是亮着的(1<=i,j,x,y<=N) 输入描述 Input

POJ 1470 Closest Common Ancestors LCA题解

本题也是找LCA的题目,不过要求多次查询,一般的暴力查询就必然超时了,故此必须使用更高级的方法,这里使用Tarjan算法. 本题处理Tarjan算法,似乎输入处理也挺麻烦的. 注意: 因为查询的数据会极大,故此使用一个数组记录所有查询数据就会超时的.我就载在这里了.查了好久才想到这点.因为我使用了一个vector容器记录了查询数据,故此每次都循环这组这么大的数据,就超时了.----解决办法:使用一个vector<int> quest来记录查询数组,这样每次都只需要循环某节点的邻接查询点就可以了

Code[VS] 1022 覆盖 题解

Code[VS] 1022 覆盖 题解 Hungary Algorithm 题目传送门:Code[VS] 1022 题目描述 Description 有一个N×M的单位方格中,其中有些方格是水塘,其他方格是陆地.如果要用1×2的矩阵区覆盖(覆盖过程不容许有任何部分重叠)这个陆地,那么最多可以覆盖多少陆地面积. 输入描述 Input Description 输入文件的第一行是两个整数N,M  (1<=N,M<=100),第二行为一个整数K( K<=50),接下来的K行,每行两个整数X,Y表

Code[VS] 2152 滑雪题解

Code[VS] 2152 滑雪题解 题目描述 Description trs喜欢滑雪.他来到了一个滑雪场,这个滑雪场是一个矩形,为了简便,我们用r行c列的矩阵来表示每块地形.为了得到更快的速度,滑行的路线必须向下倾斜.例如样例中的那个矩形,可以从某个点滑向上下左右四个相邻的点之一.例如24-17-16-1,其实25-24-23…3-2-1更长,事实上这是最长的一条. 输入描述 Input Description 输入文件 第1行: 两个数字r,c(1<=r,c<=100),表示矩阵的行列.第

寒假集训第六天---LCA题解

Gym - 100015C City Driving 题意:给你一个n个点的树再加上一条边,求询问的两个点的最短路 题解:去掉形成的环中的一条边,这样就变成了一个普通的求树上最短路,求得A1,然后求u到删掉边的u,v到删掉边的v,再加上删掉边的权值,求得A2,求v到删掉边的u,u到删掉边的v,再加上删掉边的权值w,求得A3,取最小值即可 我用的是在线倍增,为什么不用tarjan和rmq,我和他们不太熟啊 多组输入,vector忘记初始化了,爷哭了 代?? #include <bits/stdc+

LOJ6354 &amp; 洛谷4366:[Code+#4]最短路——题解

https://loj.ac/problem/6354 https://www.luogu.org/problemnew/show/P4366 题面见上面. 这题很妙,且可能是我傻,感觉这题不太好想. 前45pts很好骗就不说了. 朴素的建法是O(n^2+m)的,一个点都过不了. 然而事实上一个从x->y权值为w的边是可以被其他边取代的,我们可以把x拆成二进制,一位一位的修改最终到达y,此时经过的权值显然也是w. 也就是说,对于一个点x,我们只需要让他和x*2^k连边即可,这样就优化为O(nlo

LCA(倍增在线算法) codevs 2370 小机房的树

codevs 2370 小机房的树 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子,他们不想花费太多精力.已知从某个节点爬到其父亲节点要花费 c 的能量(从父亲节点爬到此节点也相同),他们想找出一条花费精力最短的路,以使得搞基的时候精力旺盛,他们找到你要你设计

[题解]LCA练习+部分算法复习 2017.1.22

第一题就LCA即可.不过推荐用Tarjan(最快,常数很小).然后Tarjan的时候顺便就出一个dist[i],表示i节点到根节点的距离.求出了LCA,那么两点间的距离就为dist[u] + dist[v] - 2 * dist[lca]. Code 1 #include<iostream> 2 #include<sstream> 3 #include<cstdio> 4 #include<cmath> 5 #include<cstdlib> 6