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

RMQ
树链剖分
题目描述 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问题。这里使用线段树查询解决。

代码&注释:

 /*
LCA
author:SHHHS
2016-09-26 02:25:19
*/ #include "bits/stdc++.h" using namespace std ;
typedef long long QAQ ;
struct Edge { int to , val , next ;};
struct Tree { int l , r , mintr ,pos ;};
int gmin ( int x , int y ) { return x > y ? y : x ;}
int gmax ( int x , int y ) { return x < y ? y : x ;}
const int maxN = ;
const int INF = ; Tree tr[ maxN<< ] ;
Edge e[ maxN ] ;
int cnt , dfs_num= , min_val ,min_pos ;
int head[maxN],fst[maxN],dep[maxN],ver[maxN],Dis[maxN];
bool vis[maxN]; inline void Add_Edge ( int x , int y , int _val ){
e[ ++cnt ].to = y ;
e[ cnt ].val = _val ;
e[ cnt ].next = head[ x ] ;
head[ x ] = cnt ;
} void Build_Tree ( int x , int y , int i ) {
tr[ i ].l = x ; tr[ i ].r = y ;
if ( x==y ) tr[ i ].mintr = dep[ x ] , tr[ i ].pos = x ;
else {
QAQ mid = ( tr[ i ].l + tr[ i ].r ) >> ;
Build_Tree ( x , mid , i<<);
Build_Tree ( mid+ , y , i<<|);
if (tr[i<<].mintr > tr[i<<|].mintr )
tr[ i ].pos = tr[i<<|].pos,tr[ i ].mintr = tr[i<<|].mintr;
else
tr[ i ].pos = tr[ i<< ].pos,tr[ i ].mintr = tr[ i<< ].mintr;
} } void DFS ( int x , int depth ) {
vis[ x ] = true ;
ver[ ++dfs_num ] = x ;
fst[ x ] = dfs_num ;
dep[ dfs_num ] = depth ;
for ( int i=head[ x ] ; i ; i=e[i].next ) {
int temp = e[ i ].to ;
if ( !vis[ temp ] ){
Dis[ temp ] = Dis[ x ] + e[ i ].val ;
DFS ( temp , depth + ) ;
ver[ ++dfs_num ] = x ;
dep[ dfs_num ] = depth ;
}
}
} void Query_Min ( int q , int w , int i ) {
if(q <= tr[i].l && w >= tr[i].r ){
if (tr[ i ].mintr < min_val ){
min_val = tr[i].mintr ;
min_pos = tr[i].pos ;
}
}
else {
QAQ mid = (tr[i].l + tr[i].r ) >> ;
if(q > mid) {
Query_Min ( q , w , i << | );
}
else if(w <= mid) {
Query_Min ( q , w , i << );
}
else {
Query_Min ( q , w , i << ) ;
Query_Min ( q , w , i << | );
}
}
} int LCA ( int x , int y ) {
int px = fst[ x ] , py = fst[ y ] , tmp ;
min_val = INF ;
if ( py < px ) swap ( px , py ) ;
Query_Min ( px , py , ) ;
return ver[ min_pos ] ;
}
int main ( ) {
int N ,M ;
scanf ("%d",&N);
for ( int i= ; i<=N- ; ++i ) {
int _x , _y , __ ;
scanf("%d %d %d" , &_x , &_y ,&__ ) ;
++_x;++_y;
Add_Edge ( _x , _y , __ ) ;
Add_Edge ( _y , _x , __ ) ;
}
DFS ( , ) ;
Build_Tree ( , dfs_num , ) ;
scanf ("%d",&M);
for ( int i= ; i<=M ; ++i ) {
int u , v ;
scanf ( "%d%d" , &u , &v ) ;
++u,++v;
printf ("%d",Dis[u]+Dis[v]-*Dis[LCA ( u , v )] ) ;
putchar('\n');
}
return ;
}
 /*
树链剖分
author : SHHHS
2016-9-28 14:41:17
*/
#include "bits/stdc++.h" using namespace std ;
struct Edge { int to , next , val ;};
const int maxN = ;
const int INF = ; Edge e[ maxN ] ;
int head[ maxN ], ind[ maxN ] ,start [ maxN ],pre[ maxN ],hv[maxN],DFN[maxN],Dis[maxN]; int cnt , dfs_num ; void Add_Edge ( const int _x , const int _y , const int _val ) {
e[ ++cnt ].to = _y ;
e[ cnt ].val = _val ;
e[ cnt ].next = head[ _x ] ;
head[ _x ] = cnt ;
} int Init_DFS ( const int x , const int father ) {
int cnt_ , max_ = ;
for ( int i=head[ x ] ; i ; i=e[ i ].next ) {
int temp = e[ i ].to ;
if ( temp==father ) continue ;
Dis[ temp ] = Dis[ x ] + e[ i ] .val ;
int _ = Init_DFS ( temp , x ) ;
if ( _ > max_ ) {max_ = _ ; hv[ x ] = temp ;}
cnt_ +=_;
}
return cnt_ ;
} void DFS ( const int x , const int father ) {
if ( !start[ x ] ) start[ x ] = start[ father ] ;
DFN[ x ] = ++dfs_num ;
if ( hv[ x ] ) DFS ( hv[ x ] , x ) ;
for ( int i=head[ x ] ; i ; i =e[ i ].next ) {
if ( e[ i ].to != hv[ x ] && e[i].to != father ) {
int temp = e[ i ].to ;
start[ temp ] = temp ;
pre [ temp ] = x ;
DFS ( temp , x ) ;
}
}
} int LCA ( const int x , const int y ) {
int px = x , py = y ;
while ( start[px]!=start[py] ) {
if ( DFN[start[px]]>DFN[start[py] ] ) {
px = pre[ start[px] ] ;
}
else {
py = pre[ start[py] ] ;
}
}
return DFN[px]>DFN[py]?py:px ;
}
void DEBUG_ ( int n ) {
for ( int i= ; i<=n ; ++i ) {
printf ("%d:%d\n",i,DFN[ i ] ) ;
}
}
int main ( ) {
int N , M ;
scanf ( "%d" , &N ) ;
for ( int i= ; i<=N- ; ++i ) {
int _x , _y ,_val ;
scanf ( "%d%d%d" ,&_x , &_y ,&_val ) ;
++_x;++_y;
Add_Edge ( _x , _y , _val ) ;
Add_Edge ( _y , _x , _val ) ;
} Init_DFS ( , ) ;
start[ ] = ;
DFS ( , ) ; //DEBUG_ ( N ) ; scanf ( "%d" , &M ) ;
for ( int i= ; i<=M ; ++i ) {
int u , v ;
scanf ( "%d%d" , &u , &v ) ;
++u,++v;
printf ("%d\n",Dis[ u ] + Dis[ v ] - *Dis[ LCA ( u , v ) ] ) ;
}
return ;
}
 /*
Tarjan LCA
author : SHHHS
2016-10-09 13:10:32
*/ #include "cstdio"
#include "cstring"
#include "iostream" using namespace std ;
struct Edge {int to , next , val ; } ;
struct Query { int u , v , next ; } ;
const int INF = ;
const int maxN = ; Edge e[ maxN ] ;
Query q[ maxN ] ;
int head[ maxN ] , qead[ maxN ] , father[ maxN ] , Dis[ maxN ] , lca[ maxN ] ;
bool vis[ maxN ] ; void Set_Init ( const int n ) {for ( int i= ; i<=n ; ++i ) father[ i ] = i ;} void Add_Edge ( int i , const int x , const int y , const int _val ) {
e[ i ].to = y ;
e[ i ].val = _val ;
e[ i ].next = head[ x ] ;
head[ x ] = i ;
} void Add_Query ( int i , const int x , const int y ) {
q[ i ].u = x ;
q[ i ].v = y ;
q[ i ].next = qead[ x ] ;
qead[ x ] = i ;
} int getfa ( int x ) {
return x==father[ x ] ? x : father[ x ] = getfa ( father[ x ] ) ;
} void Tarjan ( int x ) {
vis[ x ] = true ;
for ( int i=head[ x ] ; i ; i = e[ i ].next ) {
int temp = e[ i ].to ;
if ( !vis[ temp ] ) {
Dis[ temp ] = Dis[ x ] + e[ i ].val ;
Tarjan ( temp ) ;
father[ temp ] = x ;
}
} for ( int i=qead[ x ] ; i ; i = q[ i ].next ) {
int temp = q[ i ].u == x ? q[ i ].v : q[ i ].u ;
if ( vis[ temp ] )lca[ i >> ] = getfa ( father[ temp ] ) ;
}
} int getDis(int i)
{
return Dis[ q [ i << ].u ] + Dis[ q [ i << ].v ] - * Dis [ lca [ i ] ] ;
}
void DEBUG_( int n , int q ) {
for ( int i= ; i<=n ; ++i ) printf ( "%d " , Dis[ i ] ) ;
printf ( "\n" ) ;
for ( int i= ; i<=q ; ++i ) printf ( "%d " , lca[ i ] ) ;
printf ( "\n" ) ;
} int main ( ) {
int N , Q ;
scanf ( "%d" , &N ) ;
for ( int i= ; i<=N- ; ++i ) {
int _x , _y , _val ;
scanf ( "%d%d%d" , &_x , &_y , &_val ) ;
Add_Edge ( i << , _x + , _y + , _val ) ;
Add_Edge ( i << | , _y + , _x + , _val ) ;
}
scanf ( "%d" , &Q ) ;
for ( int i= ; i<=Q ; ++i ){
int _u , _v ;
scanf ( "%d%d" , &_u , &_v ) ;
Add_Query ( i << , _u + , _v + ) ;
Add_Query ( i << | , _v + , _u + ) ;
}
Set_Init ( N ) ;
Tarjan ( ) ;
//DEBUG_ ( N , Q ) ;
for ( int i= ; i<=Q ; ++i ) {
printf ( "%d\n" , getDis ( i ) ) ;
}
return ;
}

02:23:34 2016-09-26

(完)

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

  1. Code[VS] 1022 覆盖 题解

    Code[VS] 1022 覆盖 题解  Hungary Algorithm 题目传送门:Code[VS] 1022 题目描述 Description 有一个N×M的单位方格中,其中有些方格是水塘,其 ...

  2. Code[VS] 2152 滑雪题解

    Code[VS] 2152 滑雪题解 题目描述 Description trs喜欢滑雪.他来到了一个滑雪场,这个滑雪场是一个矩形,为了简便,我们用r行c列的矩阵来表示每块地形.为了得到更快的速度,滑行 ...

  3. Code[VS]1690 开关灯 题解

    Code[VS]1690 开关灯 题解     时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond   题目描述 Description:     YYX家门前 ...

  4. POJ 1330 Nearest Common Ancestors LCA题解

    Nearest Common Ancestors Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 19728   Accept ...

  5. Codeforces 965E Short Code 启发式合并 (看题解)

    Short Code 我的想法是建出字典树, 然后让后面节点最多的点优先向上移到不能移为止, 然后gg. 正确做法是对于当前的节点如果没有被占, 那么从它的子树中选出一个深度最大的点换到当前位置. 用 ...

  6. POJ 1470 Closest Common Ancestors LCA题解

    本题也是找LCA的题目,只是要求多次查询.一般的暴力查询就必定超时了,故此必须使用更高级的方法,这里使用Tarjan算法. 本题处理Tarjan算法,似乎输入处理也挺麻烦的. 注意: 由于查询的数据会 ...

  7. CODE FESTIVAL 2017 Final题解

    传送门 \(A\) 咕咕 const int N=55; const char to[]={"AKIHABARA"}; char s[N];int n; int main(){ s ...

  8. CODE FESTIVAL 2016 Final 题解

    传送门 \(A\) 什么玩意儿-- const char c[]={"snuke"}; char s[15];int n,m; int main(){ scanf("%d ...

  9. [火星补锅] 非确定性有穷状态决策自动机练习题Vol.3 T3 && luogu P4211 [LNOI2014]LCA 题解

    前言: 这题感觉还是很有意思.离线思路很奇妙.可能和二次离线有那么一点点相似?当然我不会二次离线我就不云了. 解析: 题目十分清真. 求一段连续区间内的所有点和某个给出的点的Lca的深度和. 首先可以 ...

随机推荐

  1. 使用html5 canvas绘制圆形或弧线

    注意:本文属于<html5 Canvas绘制图形入门详解>系列文章中的一部分.如果你是html5初学者,仅仅阅读本文,可能无法较深入的理解canvas,甚至无法顺畅地通读本文.请点击上述链 ...

  2. log4net的配置与使用

    log4net解决的问题是在.Net下提供一个记录日志的框架,它提供了向多种目标写入的实现,比如利用log4net可以方便地将日志信息记录到文件.控制台.Windows事件日志和数据库(包括MS SQ ...

  3. Linux环境下使用C/C++编写CGI(httpd)

    step1下载: ftp://ftp.gnu.org/gnu/cgicc/ step2: tar xzf cgicc-X.X.X.tar.gz(用最新版本) cd cgicc-X.X.X ./conf ...

  4. .net socket 层面实现代理服务器

    socket 层面实现代理服务器 首先是简一个简单的socket客户端和服务器端的例子 建立连接 Socket client = new Socket(AddressFamily.InterNetwo ...

  5. 3-1创建Sql Sever数据库登录名

    登录名:连接Sql Sever 服务器 数据库用户名: Sql Sever 的使用者 每个用来登录Sql Sever 的账户都是一个用户. 同一个数据库可以拥有多个用户,每一个用户也同时可以访问多个数 ...

  6. hdu 1851 尼姆+巴什博弈

    先在每堆中进行巴什博弈,然后尼姆 #include<stdio.h> int main() { int T; int i,n; int ans,m,l; scanf("%d&qu ...

  7. hdu 5366 组合数 *

    考虑放1个,2个....的情况,相加就是最后的结果 #include<cstdio> #include<iostream> #include<algorithm> ...

  8. css 内联元素

    内联元素又名行内元素(inline element),和其对应的是块元素(block element),都是html规范中的概念.内联元素的显示,为了帮助理解,可以形象的称为“文本模式”,即一个挨着一 ...

  9. Windows phone 8.0 本地化遇到的两个问题

    基本上来说,按照msdn来讲的,本地化和全球化没有太多的问题,链接如下: http://msdn.microsoft.com/zh-cn/library/windowsphone/develop/ff ...

  10. win10 Edge浏览器一打开就闪退崩溃的解决思路

    故障现象:从Win7.Win8.1升级到Win10,或是使用Win10一段时间后,发现Edge浏览器打开一到两秒就闪退,崩溃无法打开.解决方案: 1.尝试清理: C:\Users\Administra ...