題目鏈接:南昌邀請賽網絡賽Distance on the tree 統計一條鏈上邊權小于k的邊數。 樹上差分,對于邊權來說,一條鏈上的邊的條數=sum[x]+sum[y]-2*sum[lca(x,y)]。 對于點權來說,點數=sum[x]+sum[y]-sum[lca(x,y)]-sum[fa[lca(x,y)]]。 在求祖先的時候,需要用到樹上倍增+lca。其余的就在主席樹上去找就好了。 代碼如下:
#include <bits/stdc++.h>
#define ll long long
using namespace std
; const int maxx
= 1e5 + 100 ;
struct node
{ int l
; int r
; int sum
;
} p
[ maxx
* 20 ] ;
int head
[ maxx
<< 1 ] ;
int dp
[ maxx
] [ 22 ] ;
int val
[ maxx
] ;
int deep
[ maxx
] ;
int root
[ maxx
] ;
struct edge
{ int to
, next
, w
;
} e
[ maxx
<< 1 ] ;
int tot
, n
, m
, len
, ror
;
inline int getid ( int w
)
{ return lower_bound ( val
+ 1 , val
+ len
+ 1 , w
) - val
;
}
inline void init ( )
{ for ( int i
= 0 ; i
<= n
; i
++ ) for ( int j
= 0 ; j
<= 20 ; j
++ ) dp
[ i
] [ j
] = 0 ; memset ( head
, - 1 , sizeof ( head
) ) ; tot
= 0 ; ror
= 0 ;
}
inline void add ( int u
, int v
, int w
)
{ e
[ tot
] . to
= v
, e
[ tot
] . next
= head
[ u
] , e
[ tot
] . w
= w
, head
[ u
] = tot
++ ;
}
inline void pushup ( int cur
)
{ p
[ cur
] . sum
= p
[ p
[ cur
] . l
] . sum
+ p
[ p
[ cur
] . r
] . sum
;
}
inline int build ( int l
, int r
)
{ int cur
= ++ ror
; p
[ cur
] . sum
= 0 ; if ( l
== r
) return cur
; int mid
= l
+ r
>> 1 ; p
[ cur
] . l
= build ( l
, mid
) ; p
[ cur
] . r
= build ( mid
+ 1 , r
) ; return cur
;
}
inline int update ( int pos
, int rot
, int l
, int r
)
{ int cur
= ++ ror
; p
[ cur
] = p
[ rot
] ; if ( l
== r
) { p
[ cur
] . sum
++ ; return cur
; } int mid
= l
+ r
>> 1 ; if ( pos
<= mid
) p
[ cur
] . l
= update ( pos
, p
[ rot
] . l
, l
, mid
) ; else p
[ cur
] . r
= update ( pos
, p
[ rot
] . r
, mid
+ 1 , r
) ; pushup ( cur
) ; return cur
;
}
inline int query ( int lrot
, int rrot
, int frot
, int l
, int r
, int sum
)
{ if ( r
<= sum
) return p
[ lrot
] . sum
+ p
[ rrot
] . sum
- p
[ frot
] . sum
* 2 ; int mid
= l
+ r
>> 1 ; int ret
= p
[ p
[ lrot
] . l
] . sum
+ p
[ p
[ rrot
] . l
] . sum
- p
[ p
[ frot
] . l
] . sum
* 2 ; if ( sum
<= mid
) return query ( p
[ lrot
] . l
, p
[ rrot
] . l
, p
[ frot
] . l
, l
, mid
, sum
) ; else return ret
+ query ( p
[ lrot
] . r
, p
[ rrot
] . r
, p
[ frot
] . r
, mid
+ 1 , r
, sum
) ;
}
inline void dfs ( int u
, int f
)
{ deep
[ u
] = deep
[ f
] + 1 ; dp
[ u
] [ 0 ] = f
; for ( int i
= 1 ; i
<= 20 ; i
++ ) { if ( dp
[ u
] [ i
- 1 ] ) dp
[ u
] [ i
] = dp
[ dp
[ u
] [ i
- 1 ] ] [ i
- 1 ] ; else break ; } for ( int i
= head
[ u
] ; i
!= - 1 ; i
= e
[ i
] . next
) { int to
= e
[ i
] . to
, w
= e
[ i
] . w
; if ( to
== f
) continue ; root
[ to
] = update ( getid ( w
) , root
[ u
] , 1 , len
) ; dfs ( to
, u
) ; }
}
inline int get_lca ( int x
, int y
)
{ if ( deep
[ x
] < deep
[ y
] ) swap ( x
, y
) ; int tmp
= deep
[ x
] - deep
[ y
] ; for ( int i
= 0 ; i
<= 20 ; i
++ ) { if ( tmp
& ( 1 << i
) ) x
= dp
[ x
] [ i
] ; } if ( x
== y
) return x
; for ( int i
= 20 ; i
>= 0 ; i
-- ) { if ( dp
[ x
] [ i
] != dp
[ y
] [ i
] ) { x
= dp
[ x
] [ i
] ; y
= dp
[ y
] [ i
] ; } } return dp
[ x
] [ 0 ] ;
}
int main ( )
{ int x
, y
, w
; while ( ~ scanf ( "%d%d" , & n
, & m
) ) { init ( ) ; for ( int i
= 1 ; i
< n
; i
++ ) { scanf ( "%d%d%d" , & x
, & y
, & w
) ; add ( x
, y
, w
) ; add ( y
, x
, w
) ; val
[ i
] = w
; } sort ( val
+ 1 , val
+ n
) ; len
= unique ( val
+ 1 , val
+ n
) - val
- 1 ; root
[ 0 ] = build ( 1 , len
) ; deep
[ 0 ] = 1 ; dfs ( 1 , 0 ) ; while ( m
-- ) { scanf ( "%d%d%d" , & x
, & y
, & w
) ; int z
= get_lca ( x
, y
) ; w
= upper_bound ( val
+ 1 , val
+ len
+ 1 , w
) - val
- 1 ; if ( w
== 0 ) printf ( "0\n" ) ; else printf ( "%d\n" , query ( root
[ x
] , root
[ y
] , root
[ z
] , 1 , len
, w
) ) ; } } return 0 ;
}
努力加油a啊,(o )/~
總結
以上是生活随笔 為你收集整理的Distance on the tree(树上倍增+主席树+树上差分+lca)南昌网络赛 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。