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. Integer Inquiry【大数的加法举例】

    Integer Inquiry Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 27730   Accepted: 10764 ...

  2. [JAVA] IOException: Invalid byte 2 of 2-byte UTF-8 sequence(解决办法)

    日志打印不全,后台只打印出出标题的异常信息: 先前的日志打印信息:log.debug(e.getMessage()); 后面改成了日志打印信息:log.debug(e); log.debug(e.ge ...

  3. 在Asp.Net MVC中实现RequiredIf标签对Model中的属性进行验证

    在Asp.Net MVC中可以用继承ValidationAttribute的方式,自定制实现RequiredIf标签对Model中的属性进行验证 具体场景为:某一属性是否允许为null的验证,要根据另 ...

  4. MFC中afx_msg是什么,afx_msg void function()是什么意思

    应用程序框架产生的消息映射函数例如:afx_msg void OnBnClickedButton1(); 其中 afx_msg为消息标志,它向系统声明:有消息映射到函数实现体:而在map宏定义中,就有 ...

  5. codeforces724-A. Checking the Calendar 日期题

    首先有这样一个显然的事实,那就是每个月的第一天可以是星期x,x可以取遍1~7 因为日期一直在往后退,总有一年能轮到分割线那天,因为本来其实压根就没有月份的划分,月份划分是人为的 而且我们也不知道开始的 ...

  6. 梳理源码中 View 的工作原理

    欢迎Follow我的GitHub, 关注我的掘金. 在View的工作过程中, 执行三大流程完成显示, 测量(measure)流程, 布局(layout)流程, 绘制(draw)流程. 从perform ...

  7. JMeter性能监测插件介绍(三)

    JMeter 性能监测插件介绍 压力测试过程中,能够随时对负载服务器的健康状况的把控是相当重要的,有了这些数据,我们才能准确分析出服务器负载瓶颈.JMeter 插件包现在能够支持服务器监控,可以在所有 ...

  8. 如何在Crystal Portlet中正确返回JSON数据给AJAX请求?

    当Crystal Portlet中需要采用Ajax请求,并让后台返回Json数据时,如何才能正确.方便的返回Json数据呢? 以下两种方法均可: 方法一:Ajax请求时,采用RenderURL,对应P ...

  9. Java Android 注解(Annotation) 及几个常用开源项目注解原理简析

    不少开源库(ButterKnife.Retrofit.ActiveAndroid等等)都用到了注解的方式来简化代码提高开发效率. 本文简单介绍下 Annotation 示例.概念及作用.分类.自定义. ...

  10. 【hdu3948-不同回文串的个数】后缀数组

    题意:求不同回文串的个数 n<=10^5 题解: 先按照manacher的构造方法改造一遍串,然后跑一遍manacher. 如ababa--> $#a#b#a#b#a#@ 然后跑一遍后缀数 ...