Code[VS] 2370 LCA 题解
Code[VS] 2370 小机房的树 题解
小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上。有一天,他们想爬到一个节点上去搞基,但是作为两只虫子,他们不想花费太多精力。已知从某个节点爬到其父亲节点要花费 c 的能量(从父亲节点爬到此节点也相同),他们想找出一条花费精力最短的路,以使得搞基的时候精力旺盛,他们找到你要你设计一个程序来找到这条路,要求你告诉他们最少需要花费多少精力
第一行一个n,接下来n-1行每一行有三个整数u,v, c 。表示节点 u 爬到节点 v 需要花费 c 的精力。
第n+1行有一个整数m表示有m次询问。接下来m行每一行有两个整数 u ,v 表示两只虫子所在的节点
一共有m行,每一行一个整数,表示对于该次询问所得出的最短距离。
3
1 0 1
2 0 1
3
1 0
2 0
1 2
1
1
2
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 题解的更多相关文章
- Code[VS] 1022 覆盖 题解
Code[VS] 1022 覆盖 题解 Hungary Algorithm 题目传送门:Code[VS] 1022 题目描述 Description 有一个N×M的单位方格中,其中有些方格是水塘,其 ...
- Code[VS] 2152 滑雪题解
Code[VS] 2152 滑雪题解 题目描述 Description trs喜欢滑雪.他来到了一个滑雪场,这个滑雪场是一个矩形,为了简便,我们用r行c列的矩阵来表示每块地形.为了得到更快的速度,滑行 ...
- Code[VS]1690 开关灯 题解
Code[VS]1690 开关灯 题解 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description: YYX家门前 ...
- POJ 1330 Nearest Common Ancestors LCA题解
Nearest Common Ancestors Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 19728 Accept ...
- Codeforces 965E Short Code 启发式合并 (看题解)
Short Code 我的想法是建出字典树, 然后让后面节点最多的点优先向上移到不能移为止, 然后gg. 正确做法是对于当前的节点如果没有被占, 那么从它的子树中选出一个深度最大的点换到当前位置. 用 ...
- POJ 1470 Closest Common Ancestors LCA题解
本题也是找LCA的题目,只是要求多次查询.一般的暴力查询就必定超时了,故此必须使用更高级的方法,这里使用Tarjan算法. 本题处理Tarjan算法,似乎输入处理也挺麻烦的. 注意: 由于查询的数据会 ...
- CODE FESTIVAL 2017 Final题解
传送门 \(A\) 咕咕 const int N=55; const char to[]={"AKIHABARA"}; char s[N];int n; int main(){ s ...
- CODE FESTIVAL 2016 Final 题解
传送门 \(A\) 什么玩意儿-- const char c[]={"snuke"}; char s[15];int n,m; int main(){ scanf("%d ...
- [火星补锅] 非确定性有穷状态决策自动机练习题Vol.3 T3 && luogu P4211 [LNOI2014]LCA 题解
前言: 这题感觉还是很有意思.离线思路很奇妙.可能和二次离线有那么一点点相似?当然我不会二次离线我就不云了. 解析: 题目十分清真. 求一段连续区间内的所有点和某个给出的点的Lca的深度和. 首先可以 ...
随机推荐
- Java集合源码学习(一)集合框架概览
>>集合框架 Java集合框架包含了大部分Java开发中用到的数据结构,主要包括List列表.Set集合.Map映射.迭代器(Iterator.Enumeration).工具类(Array ...
- C# 设计模式 提高可维护性的几点原则
为了提高软件的可维护性,应该遵循以下几点原则: 1.“开放--封闭”原则(OCP) 一个软件实体应该对扩展开放,对修改封闭. 2.里氏代换原则(LSP) 子类型必须能替换她们的基类型,反过来则不成立. ...
- HDU4288 Coder(线段树)
注意添加到集合中的数是升序的,先将数据读入,再离散化. sum[rt][i]表示此节点的区域位置对5取模为i的数的和,删除一个数则右边的数循环左移一位,添加一个数则右边数循环右移一位,相当于循环左移4 ...
- 攻城狮在路上(叁)Linux(二十六)--- linux文件系统的特殊查看与操作
一.boot sector 与 super block的关系: 1.boot sector用于存放引导装载程序,占用1024个字节. 2.super block的大小也为1024字节. 3.若bloc ...
- java Integer == 比较的小问题
示例代码: @Test public void testEquals() { Integer a = 127; Integer b = 127; if(a == b) { System.out.pri ...
- ARM指令学习,王明学learn
ARM指令学习 一.算数和逻辑指令 1— MOV 数据传送指令 2.— MVN 数据取反传送指令 3.— CMP 比较指令 4.— CMN 反值比较指令 5.— TST 位测试 ...
- loj 1377 (bfs)
题目链接:http://lightoj.com/volume_showproblem.php?problem=1377 思路:这道题只要处理好遇到"*"这种情况就可以搞定了.我们可 ...
- ios广告
ios广告只需要添加iAd.framework框架 添加广告控件ADBannerView,在控制器中设置广告控件代理<ADBannerViewDelegate>即可,广告会有苹果官方自动推 ...
- Win7 Object_Header之TypeIndex解析
在暴力搜索内存进程对象反隐藏进程这篇文章中,我们提到: Object Header偏移0×008处Type成员为对象类型值,相同类型的对象具有相同的值. 自Window 7开始, _OBJECT_ ...
- Linux下autoconf和automake使用
转载:www.cnblogs.com/itech/archive/2010/11/28/1890220.html