生活随笔
收集整理的這篇文章主要介紹了
codeforces contest 1140(D~G)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
前言
A~C不想寫博客了,就不寫了,后面的題還是要推一推的,所以寫一下
CF 1140 D
題目大意 : 給出一個正多邊形,頂點按順序標號為11 1 ~nn n ,一個三角劃分的權值是每個三角形三個頂點的編號乘積之和 求出一個三角劃分使得這個三角劃分的權值是所有的中最小的 n≤500n\le500 n ≤ 5 0 0 題解: 區間dp即可,挺方便的,復雜度O(n3)\mathcal O(n^3) O ( n 3 ) 但是事實上,這題是個結論題,可以直接O(1)\mathcal O(1) O ( 1 ) 計算的 我們來進行一下推導 我們考慮11 1 到nn n 的邊1-n,假設其所在的三角劃分是Δ\Delta Δ 1-x-n 如果x≠n?1x\neq n-1 x ? ? = n ? 1 ,那么邊x-n一定在另一個三角劃分Δ\Delta Δ x-k-n(k>xk>x k > x )中 我們考慮這兩個三角劃分構成的四邊形(此處貼了一幅圖,可以根據圖來理解下面的證明 ) 我們把這兩個三角劃分 Δ\Delta Δ 1-x-n+Δ\Delta Δ x-k-n改成Δ\Delta Δ 1-x-k+Δ\Delta Δ 1-k-n 我們發現值會嚴格變小,即 1?x?n+x?k?n>1?x?k+1?k?n1*x*n+x*k*n>1*x*k+1*k*n 1 ? x ? n + x ? k ? n > 1 ? x ? k + 1 ? k ? n 這個不等式很顯然吧,是由兩個不等式加在一起的 x?k?n>1?k?nx*k*n>1*k*n x ? k ? n > 1 ? k ? n ,1?x?n>1?x?k1*x*n>1*x*k 1 ? x ? n > 1 ? x ? k 這樣不停操作,我們發現最后xx x 就是n?1n-1 n ? 1 了,然后又轉化成子問題(即nn n 減小了11 1 ),所以最后的答案一定是所有三角劃分都有11 1 這個頂點 那么答案就是 ∏i=2n?1i?(i+1)\prod_{i=2}^{n-1}i*(i+1) i = 2 ∏ n ? 1 ? i ? ( i + 1 ) 直接轉化成 ∏i=2n?1i2+i\prod_{i=2}^{n-1}i^2+i i = 2 ∏ n ? 1 ? i 2 + i 直接平方和公式和等差數列求和公式代入即可
#include <bits/stdc++.h>
typedef long long ll
;
#define rg register
template
< typename T
> inline void read ( T
& x
) { char cu
= getchar ( ) ; x
= 0 ; bool fla
= 0 ; while ( ! isdigit ( cu
) ) { if ( cu
== '-' ) fla
= 1 ; cu
= getchar ( ) ; } while ( isdigit ( cu
) ) x
= x
* 10 + cu
- '0' , cu
= getchar ( ) ; if ( fla
) x
= - x
; }
template
< typename T
> inline void printe ( const T x
) { if ( x
>= 10 ) printe ( x
/ 10 ) ; putchar ( x
% 10 + '0' ) ; }
template
< typename T
> inline void print ( const T x
) { if ( x
< 0 ) putchar ( '-' ) , printe ( - x
) ; else printe ( x
) ; }
template
< typename T
> inline T
min ( const T a
, const T b
) { return a
< b
? a
: b
; }
template
< typename T
> inline T
max ( const T a
, const T b
) { return a
> b
? a
: b
; }
int n
;
int main ( )
{ read ( n
) ; print ( ( n
- 1 ) * n
* ( n
* 2 - 1 ) / 6 + n
* ( n
- 1 ) / 2 - 2 ) ; return 0 ;
}
CF 1140 E
題目大意 :給定一個值域為kk k 的序列,有些位置還沒有填上數,求有多少種填數方式使得這個序列不存在非1奇長度回文子串 n,k≤2?105n,k\le2·10^5 n , k ≤ 2 ? 1 0 5 題解: 這里有個奇 長度回文子串,這是非常好的性質,我們發現如果對于任何ii i 均滿足ai≠ai+2a_i\neq a_{i+2} a i ? ? ? = a i + 2 ? ,那么這個序列就是合法的 那么我們可以把奇數、偶數位單獨拖出來,就變成了子問題,有多少種填法使得沒有相鄰數相同(這個可以直接dp做),奇偶串答案相乘即可 復雜度O(n)\mathcal O(n) O ( n )
#include <bits/stdc++.h>
typedef long long ll
;
#define rg register
template
< typename T
> inline void read ( T
& x
) { char cu
= getchar ( ) ; x
= 0 ; bool fla
= 0 ; while ( ! isdigit ( cu
) ) { if ( cu
== '-' ) fla
= 1 ; cu
= getchar ( ) ; } while ( isdigit ( cu
) ) x
= x
* 10 + cu
- '0' , cu
= getchar ( ) ; if ( fla
) x
= - x
; }
template
< typename T
> inline void printe ( const T x
) { if ( x
>= 10 ) printe ( x
/ 10 ) ; putchar ( x
% 10 + '0' ) ; }
template
< typename T
> inline void print ( const T x
) { if ( x
< 0 ) putchar ( '-' ) , printe ( - x
) ; else printe ( x
) ; }
template
< typename T
> inline T
min ( const T a
, const T b
) { return a
< b
? a
: b
; }
template
< typename T
> inline T
max ( const T a
, const T b
) { return a
> b
? a
: b
; }
const int mod
= 998244353 ;
int n
, k
, a
[ 200001 ] , b
[ 200001 ] , ta
, tb
;
ll A
[ 200001 ] , B
[ 200001 ] , C
[ 200001 ] ;
ll ans
= 1 ;
int main ( )
{ read ( n
) , read ( k
) ; for ( rg
int i
= 1 ; i
<= n
; i
++ ) if ( i
& 1 ) read ( a
[ ++ ta
] ) ; else read ( b
[ ++ tb
] ) ; A
[ 1 ] = k
- 1 , B
[ 1 ] = k
- 2 , C
[ 1 ] = k
- 1 ; A
[ 0 ] = B
[ 0 ] = C
[ 0 ] = 1 ; for ( rg
int i
= 2 ; i
<= n
; i
++ ) { A
[ i
] = B
[ i
- 1 ] * ( k
- 1 ) % mod
; B
[ i
] = ( B
[ i
- 1 ] * ( k
- 2 ) + A
[ i
- 1 ] ) % mod
; C
[ i
] = C
[ i
- 1 ] * ( k
- 1 ) % mod
; } for ( rg
int i
= 1 ; i
<= ta
; i
++ ) if ( a
[ i
] == - 1 ) { int j
= i
; while ( j
< ta
&& a
[ j
+ 1 ] == - 1 ) j
++ ; if ( i
== 1 && j
== ta
) ans
= ans
* C
[ ta
- 1 ] % mod
* k
% mod
; else if ( i
== 1 || j
== ta
) ans
= ans
* C
[ j
- i
+ 1 ] % mod
; else if ( a
[ i
- 1 ] == a
[ j
+ 1 ] ) ans
= ans
* A
[ j
- i
+ 1 ] % mod
; else ans
= ans
* B
[ j
- i
+ 1 ] % mod
; i
= j
+ 1 ; } else if ( i
!= ta
&& a
[ i
+ 1 ] != - 1 && a
[ i
] == a
[ i
+ 1 ] ) ans
= 0 ; for ( rg
int i
= 1 ; i
<= tb
; i
++ ) if ( b
[ i
] == - 1 ) { int j
= i
; while ( j
< tb
&& b
[ j
+ 1 ] == - 1 ) j
++ ; if ( i
== 1 && j
== tb
) ans
= ans
* C
[ tb
- 1 ] % mod
* k
% mod
; else if ( i
== 1 || j
== tb
) ans
= ans
* C
[ j
- i
+ 1 ] % mod
; else if ( b
[ i
- 1 ] == b
[ j
+ 1 ] ) ans
= ans
* A
[ j
- i
+ 1 ] % mod
; else ans
= ans
* B
[ j
- i
+ 1 ] % mod
; i
= j
+ 1 ; } else if ( i
!= tb
&& b
[ i
+ 1 ] != - 1 && b
[ i
] == b
[ i
+ 1 ] ) ans
= 0 ; print ( ans
) ; return 0 ;
}
CF 1140 F
題目大意 :在平面直角坐標系中,如果有3個點能作為一個矩形(邊平行于坐標軸)的三個頂點,那么我們可以把這個矩形的第四個點也加入點集,直到不能再加入 設當前點集為SS S ,不斷的進行操作使得點集變為TT T 現在給出若干點集SS S 求每個對應的∣T∣|T| ∣ T ∣ 給出的方式是每次加入一個點或者刪除一個點 q≤3?105,1≤xi,yi≤3?105q\le3·10^5,1\le x_i,y_i\le3·10^5 q ≤ 3 ? 1 0 5 , 1 ≤ x i ? , y i ? ≤ 3 ? 1 0 5 題解: 這題真爽 我們考慮假如只有加點操作 我們對于所有坐標點,如果有兩個點橫坐標/縱坐標相同,那么我們視為這兩個點是聯通的 要求的就是所有聯通快的不同橫坐標數量乘以不同縱坐標數量的和 我們發現這個東西大概要開set之類的維護,不是很方便,并且在貢獻答案的時候會有一些特判(所有單獨點的聯通快顯然都貢獻1,但是如果這個點根本沒有,那就貢獻0) 方便起見,考慮優化 我們拆點,把橫坐標的位置、縱坐標的位置拆開,這樣每個點的加入視為連一條邊,這個時候維護不同橫坐標數量、不同縱坐標數量就很方便了,直接加就好了,還不會有貢獻答案的問題(我們發現這個時候單獨一個點的貢獻是0,而加入一條連向一個橫坐標和一個縱坐標的邊時能貢獻1) 考慮如何解決刪點的情況 我們發現如果一個點被刪除了,那么他貢獻答案的地方一定是一個區間,我們直接用線段樹維護區間即可,那么一次插入會到O(logq)\mathcal O(logq) O ( l o g q ) 條線段樹上 考慮如何處理出每個葉子節點的答案,經典套路,直接dfs即可,然后用可持久化并查集維護并查集,由于不能路徑壓縮、只能按秩合并,所以并查集復雜度是O(logq)\mathcal O(logq) O ( l o g q ) 的 總復雜度O(qlog2q)\mathcal O(qlog^2q) O ( q l o g 2 q ) (本題后文有彩蛋,請一定要觀看 )
#include <bits/stdc++.h>
typedef long long ll
;
#define rg register
template
< typename T
> inline void read ( T
& x
) { char cu
= getchar ( ) ; x
= 0 ; bool fla
= 0 ; while ( ! isdigit ( cu
) ) { if ( cu
== '-' ) fla
= 1 ; cu
= getchar ( ) ; } while ( isdigit ( cu
) ) x
= x
* 10 + cu
- '0' , cu
= getchar ( ) ; if ( fla
) x
= - x
; }
template
< typename T
> inline void printe ( const T x
) { if ( x
>= 10 ) printe ( x
/ 10 ) ; putchar ( x
% 10 + '0' ) ; }
template
< typename T
> inline void print ( const T x
) { if ( x
< 0 ) putchar ( '-' ) , printe ( - x
) ; else printe ( x
) ; }
template
< typename T
> inline T
min ( const T a
, const T b
) { return a
< b
? a
: b
; }
template
< typename T
> inline T
max ( const T a
, const T b
) { return a
> b
? a
: b
; }
const int MAX
= 2097152 ;
int q
, l
[ MAX
] , r
[ MAX
] , mid
[ MAX
] ;
std
: : vector
< std
: : pair
< int , int > > irt
[ MAX
] ;
std
: : vector
< std
: : pair
< int , int > > : : iterator pos
;
void ini ( const int root
, const int ll
, const int rr
)
{ l
[ root
] = ll
, r
[ root
] = rr
, mid
[ root
] = ( ll
+ rr
) >> 1 ; if ( ll
== rr
) return ; ini ( root
<< 1 , ll
, mid
[ root
] ) , ini ( root
<< 1 | 1 , mid
[ root
] + 1 , rr
) ;
}
void insert ( const int root
, const int wanl
, const int wanr
, std
: : pair
< int , int > V
)
{ if ( wanl
== l
[ root
] && wanr
== r
[ root
] ) { irt
[ root
] . push_back ( V
) ; return ; } if ( wanr
<= mid
[ root
] ) insert ( root
<< 1 , wanl
, wanr
, V
) ; else if ( wanl
> mid
[ root
] ) insert ( root
<< 1 | 1 , wanl
, wanr
, V
) ; else insert ( root
<< 1 , wanl
, mid
[ root
] , V
) , insert ( root
<< 1 | 1 , mid
[ root
] + 1 , wanr
, V
) ;
}
struct P
{ int a
, b
, t
; bool operator
< ( const P B
) const { return a
== B
. a
? b
< B
. b
: a
< B
. a
; }
} ;
std
: : set
< P
> Q
;
std
: : set
< P
> : : iterator Pos
;
struct info
{ int v
, a
, b
; void clear ( ) { v
= a
= b
= 0 ; }
} ;
struct node
{ node
* lson
, * rson
; info v
;
} t
[ 12600021 ] , * root
[ 600001 ] , empty
, * Null
;
int usdto
[ 600001 ] , id
;
node
* newnode ( )
{ node
* R
= & t
[ ++ usdto
[ id
] ] ; R
-> lson
= R
-> rson
= Null
, R
-> v
. clear ( ) ; return R
;
}
int pl
; info val
;
void INSERT ( node
* las
, node
* dq
, const int root
)
{ if ( l
[ root
] == r
[ root
] ) { dq
-> v
= val
; return ; } if ( pl
<= mid
[ root
] ) INSERT ( las
-> lson
, dq
-> lson
= newnode ( ) , root
<< 1 ) , dq
-> rson
= las
-> rson
; else INSERT ( las
-> rson
, dq
-> rson
= newnode ( ) , root
<< 1 | 1 ) , dq
-> lson
= las
-> lson
;
}
info RES
;
void SEARCH ( node
* dq
, const int root
, const int pl
)
{ if ( l
[ root
] == r
[ root
] ) { if ( dq
-> v
. v
== 0 ) RES
= ( info
) { pl
, pl
<= 300000 , pl
> 300000 } ; else RES
= dq
-> v
; return ; } if ( pl
<= mid
[ root
] ) SEARCH ( dq
-> lson
, root
<< 1 , pl
) ; else SEARCH ( dq
-> rson
, root
<< 1 | 1 , pl
) ;
}
ll ans
[ 600001 ] ;
info
find ( const int x
)
{ SEARCH ( root
[ id
] , 1 , x
) ; info u
= RES
; if ( u
. v
== x
) return u
; return find ( u
. v
) ;
}
void dodo ( std
: : pair
< int , int > V
)
{
V
. second
+ = 300000 ; info u
= find ( V
. first
) , v
= find ( V
. second
) ; if ( u
. v
== v
. v
) id
+ = 2 , usdto
[ id
] = usdto
[ id
- 2 ] , root
[ id
] = root
[ id
- 2 ] , ans
[ id
] = ans
[ id
- 2 ] ; else { if ( u
. a
+ u
. b
< v
. a
+ v
. b
) std
: : swap ( u
, v
) ; id
++ , usdto
[ id
] = usdto
[ id
- 1 ] ; root
[ id
] = newnode ( ) ; pl
= v
. v
, val
= ( info
) { u
. v
, 0 , 0 } ; INSERT ( root
[ id
- 1 ] , root
[ id
] , 1 ) ; id
++ , usdto
[ id
] = usdto
[ id
- 1 ] ; root
[ id
] = newnode ( ) ; pl
= u
. v
, val
= ( info
) { u
. v
, u
. a
+ v
. a
, u
. b
+ v
. b
} ; INSERT ( root
[ id
- 1 ] , root
[ id
] , 1 ) ; ans
[ id
] = ans
[ id
- 2 ] ; ans
[ id
] + = ( ll
) ( u
. a
+ v
. a
) * ( u
. b
+ v
. b
) - ( ll
) u
. a
* u
. b
- ( ll
) v
. a
* v
. b
; }
}
void undo ( )
{
id
- = 2 ;
}
void dfs ( const int root
)
{ if ( l
[ root
] > q
) return ;
for ( pos
= irt
[ root
] . begin ( ) ; pos
!= irt
[ root
] . end ( ) ; pos
++ ) dodo ( * pos
) ; if ( l
[ root
] == r
[ root
] ) print ( ans
[ id
] ) , putchar ( ' ' ) ; else dfs ( root
<< 1 ) , dfs ( root
<< 1 | 1 ) ; for ( pos
= irt
[ root
] . begin ( ) ; pos
!= irt
[ root
] . end ( ) ; pos
++ ) undo ( ) ;
}
int main ( )
{ empty
. lson
= empty
. rson
= Null
= & empty
; root
[ 0 ] = newnode ( ) ; read ( q
) ; ini ( 1 , 1 , 600000 ) ; for ( rg
int i
= 1 ; i
<= q
; i
++ ) { P u
; read ( u
. a
) , read ( u
. b
) ; if ( ( Pos
= Q
. find ( u
) ) == Q
. end ( ) ) { u
. t
= i
; Q
. insert ( u
) ; } else { insert ( 1 , ( * Pos
) . t
, i
- 1 , std
: : make_pair ( ( * Pos
) . a
, ( * Pos
) . b
) ) ; Q
. erase ( Pos
) ; } } while ( Q
. size ( ) ) { Pos
= Q
. begin ( ) ; insert ( 1 , ( * Pos
) . t
, q
, std
: : make_pair ( ( * Pos
) . a
, ( * Pos
) . b
) ) ; Q
. erase ( Pos
) ; } dfs ( 1 ) ; return 0 ;
}
xswl,我以為可持久化并查集是對的,其實是3個log的,T成大傻逼 上面貼出的是TLE代碼 并查集是其實是可以O(1)\mathcal O(1) O ( 1 ) 撤銷的,只能重寫
#include <bits/stdc++.h>
typedef long long ll
;
#define rg register
template
< typename T
> inline void read ( T
& x
) { char cu
= getchar ( ) ; x
= 0 ; bool fla
= 0 ; while ( ! isdigit ( cu
) ) { if ( cu
== '-' ) fla
= 1 ; cu
= getchar ( ) ; } while ( isdigit ( cu
) ) x
= x
* 10 + cu
- '0' , cu
= getchar ( ) ; if ( fla
) x
= - x
; }
template
< typename T
> inline void printe ( const T x
) { if ( x
>= 10 ) printe ( x
/ 10 ) ; putchar ( x
% 10 + '0' ) ; }
template
< typename T
> inline void print ( const T x
) { if ( x
< 0 ) putchar ( '-' ) , printe ( - x
) ; else printe ( x
) ; }
template
< typename T
> inline T
min ( const T a
, const T b
) { return a
< b
? a
: b
; }
template
< typename T
> inline T
max ( const T a
, const T b
) { return a
> b
? a
: b
; }
const int MAX
= 2097152 ;
int q
, l
[ MAX
] , r
[ MAX
] , mid
[ MAX
] ;
std
: : vector
< std
: : pair
< int , int > > irt
[ MAX
] ;
std
: : vector
< std
: : pair
< int , int > > : : iterator pos
;
void ini ( const int root
, const int ll
, const int rr
)
{ l
[ root
] = ll
, r
[ root
] = rr
, mid
[ root
] = ( ll
+ rr
) >> 1 ; if ( ll
== rr
) return ; ini ( root
<< 1 , ll
, mid
[ root
] ) , ini ( root
<< 1 | 1 , mid
[ root
] + 1 , rr
) ;
}
void insert ( const int root
, const int wanl
, const int wanr
, std
: : pair
< int , int > V
)
{ if ( wanl
== l
[ root
] && wanr
== r
[ root
] ) { irt
[ root
] . push_back ( V
) ; return ; } if ( wanr
<= mid
[ root
] ) insert ( root
<< 1 , wanl
, wanr
, V
) ; else if ( wanl
> mid
[ root
] ) insert ( root
<< 1 | 1 , wanl
, wanr
, V
) ; else insert ( root
<< 1 , wanl
, mid
[ root
] , V
) , insert ( root
<< 1 | 1 , mid
[ root
] + 1 , wanr
, V
) ;
}
struct P
{ int a
, b
, t
; bool operator
< ( const P B
) const { return a
== B
. a
? b
< B
. b
: a
< B
. a
; }
} ;
std
: : set
< P
> Q
;
std
: : set
< P
> : : iterator Pos
;
ll ans
;
int bcj
[ 600001 ] , ltot
[ 600001 ] , rtot
[ 600001 ] ;
int find ( const int x
)
{ if ( x
== bcj
[ x
] ) return x
; return find ( bcj
[ x
] ) ;
}
int cha
[ 600001 ] , chb
[ 600001 ] , opt
;
void dodo ( std
: : pair
< int , int > V
)
{ V
. second
+ = 300000 ; int u
= find ( V
. first
) , v
= find ( V
. second
) ; opt
++ ; if ( u
== v
) cha
[ opt
] = 0 ; else { if ( ltot
[ u
] + rtot
[ u
] < ltot
[ v
] + rtot
[ v
] ) std
: : swap ( u
, v
) ; bcj
[ v
] = u
; ans
+ = ( ll
) ( ltot
[ u
] + ltot
[ v
] ) * ( rtot
[ u
] + rtot
[ v
] ) - ( ll
) ltot
[ u
] * rtot
[ u
] - ( ll
) ltot
[ v
] * rtot
[ v
] ; ltot
[ u
] + = ltot
[ v
] ; rtot
[ u
] + = rtot
[ v
] ; cha
[ opt
] = u
, chb
[ opt
] = v
; }
}
void undo ( )
{ if ( cha
[ opt
] ) { int u
= cha
[ opt
] , v
= chb
[ opt
] ; ltot
[ u
] - = ltot
[ v
] ; rtot
[ u
] - = rtot
[ v
] ; ans
- = ( ll
) ( ltot
[ u
] + ltot
[ v
] ) * ( rtot
[ u
] + rtot
[ v
] ) - ( ll
) ltot
[ u
] * rtot
[ u
] - ( ll
) ltot
[ v
] * rtot
[ v
] ; bcj
[ v
] = v
; } opt
-- ;
}
void dfs ( const int root
)
{ for ( pos
= irt
[ root
] . begin ( ) ; pos
!= irt
[ root
] . end ( ) ; pos
++ ) dodo ( * pos
) ; if ( l
[ root
] == r
[ root
] ) print ( ans
) , putchar ( ' ' ) ; else dfs ( root
<< 1 ) , dfs ( root
<< 1 | 1 ) ; for ( pos
= irt
[ root
] . begin ( ) ; pos
!= irt
[ root
] . end ( ) ; pos
++ ) undo ( ) ;
}
int main ( )
{ for ( rg
int i
= 1 ; i
<= 600000 ; i
++ ) { bcj
[ i
] = i
; if ( i
<= 300000 ) ltot
[ i
] ++ ; else rtot
[ i
] ++ ; } read ( q
) ; ini ( 1 , 1 , q
) ; for ( rg
int i
= 1 ; i
<= q
; i
++ ) { P u
; read ( u
. a
) , read ( u
. b
) ; if ( ( Pos
= Q
. find ( u
) ) == Q
. end ( ) ) { u
. t
= i
; Q
. insert ( u
) ; } else { insert ( 1 , ( * Pos
) . t
, i
- 1 , std
: : make_pair ( ( * Pos
) . a
, ( * Pos
) . b
) ) ; Q
. erase ( Pos
) ; } } while ( Q
. size ( ) ) { Pos
= Q
. begin ( ) ; insert ( 1 , ( * Pos
) . t
, q
, std
: : make_pair ( ( * Pos
) . a
, ( * Pos
) . b
) ) ; Q
. erase ( Pos
) ; } dfs ( 1 ) ; return 0 ;
}
CF 1140 G
題目大意 : 給出一棵nn n 個節點的樹,然后將這棵樹復制一遍,并且復制后與復制前的點連邊,兩棵樹內部分別有樹邊 這些所有邊都有邊權 qq q 組詢問,每次給出兩個點,求兩個點之間的最短路 n≤3?105,q≤6?105n\le 3·10^5,q\le6·10^5 n ≤ 3 ? 1 0 5 , q ≤ 6 ? 1 0 5 題解: 看起來好像是求圖上最短路 但實際上我們發現,這還是一個樹上最短路問題 考慮我們是怎么求樹上最短路的——求lca,然后深度減一下即可 對于這道題,我們考慮,最短路一定會經過lca在第一棵樹上的點或者是lca在第二棵樹上的點,所以我們如果能處理處一個倍增數組fi,j,k,lf_{i,j,k,l} f i , j , k , l ? (i,j∈[1,n],k,l∈[0,1]i,j\in[1,n],k,l\in[0,1] i , j ∈ [ 1 , n ] , k , l ∈ [ 0 , 1 ] )表示編號為ii i 的點在第kk k 棵樹上到其的2j2^j 2 j 祖先在第ll l 棵樹上的最短路 考慮如何轉移,我們發現只需要求出所有的gig_i g i ? 表示樹上ii i 這個節點所對應的兩個節點之間的最短路長度即可 我們發現gg g 可以兩遍dfs求得,然后ff f 也可以求出,最后就只要對于每個詢問倍增就好了 復雜度O(nlogn)\mathcal O(nlogn) O ( n l o g n )
#include <bits/stdc++.h>
typedef long long ll
;
#define rg register
template
< typename T
> inline void read ( T
& x
) { char cu
= getchar ( ) ; x
= 0 ; bool fla
= 0 ; while ( ! isdigit ( cu
) ) { if ( cu
== '-' ) fla
= 1 ; cu
= getchar ( ) ; } while ( isdigit ( cu
) ) x
= x
* 10 + cu
- '0' , cu
= getchar ( ) ; if ( fla
) x
= - x
; }
template
< typename T
> inline void printe ( const T x
) { if ( x
>= 10 ) printe ( x
/ 10 ) ; putchar ( x
% 10 + '0' ) ; }
template
< typename T
> inline void print ( const T x
) { if ( x
< 0 ) putchar ( '-' ) , printe ( - x
) ; else printe ( x
) ; }
template
< typename T
> inline T
min ( const T a
, const T b
) { return a
< b
? a
: b
; }
template
< typename T
> inline T
max ( const T a
, const T b
) { return a
> b
? a
: b
; }
template
< typename T
> inline void mind ( T
& a
, const T b
) { a
= a
< b
? a
: b
; }
const int maxn
= 300001 , maxm
= 600001 ;
int n
, q
, dep
[ maxn
] ;
int head
[ maxn
] , nxt
[ maxm
] , tow
[ maxm
] , tmp
; ll vau1
[ maxm
] , vau2
[ maxm
] ;
inline void addb ( const int u
, const int v
, const ll w1
, const ll w2
)
{ tmp
++ ; nxt
[ tmp
] = head
[ u
] ; head
[ u
] = tmp
; tow
[ tmp
] = v
; vau1
[ tmp
] = w1
; vau2
[ tmp
] = w2
;
}
ll g
[ maxn
] ;
void dfs1 ( const int u
, const int fa
)
{ for ( rg
int i
= head
[ u
] ; i
; i
= nxt
[ i
] ) { const int v
= tow
[ i
] ; if ( v
== fa
) continue ; dep
[ v
] = dep
[ u
] + 1 ; dfs1 ( v
, u
) ; g
[ u
] = min ( g
[ u
] , vau1
[ i
] + vau2
[ i
] + g
[ v
] ) ; }
}
ll f
[ maxn
] [ 21 ] [ 2 ] [ 2 ] ; int p
[ maxn
] [ 21 ] ;
void dfs2 ( const int u
, const int fa
)
{ for ( rg
int i
= head
[ u
] ; i
; i
= nxt
[ i
] ) { const int v
= tow
[ i
] ; if ( v
== fa
) continue ; g
[ v
] = min ( g
[ v
] , vau1
[ i
] + vau2
[ i
] + g
[ u
] ) ; f
[ v
] [ 0 ] [ 0 ] [ 0 ] = vau1
[ i
] ; f
[ v
] [ 0 ] [ 0 ] [ 1 ] = g
[ v
] + vau2
[ i
] ; mind ( f
[ v
] [ 0 ] [ 0 ] [ 0 ] , f
[ v
] [ 0 ] [ 0 ] [ 1 ] + g
[ u
] ) ; mind ( f
[ v
] [ 0 ] [ 0 ] [ 1 ] , f
[ v
] [ 0 ] [ 0 ] [ 0 ] + g
[ u
] ) ; f
[ v
] [ 0 ] [ 1 ] [ 0 ] = g
[ v
] + vau1
[ i
] ; f
[ v
] [ 0 ] [ 1 ] [ 1 ] = vau2
[ i
] ; mind ( f
[ v
] [ 0 ] [ 1 ] [ 0 ] , f
[ v
] [ 0 ] [ 1 ] [ 1 ] + g
[ u
] ) ; mind ( f
[ v
] [ 0 ] [ 1 ] [ 1 ] , f
[ v
] [ 0 ] [ 1 ] [ 0 ] + g
[ u
] ) ; p
[ v
] [ 0 ] = u
; dfs2 ( v
, u
) ; }
}
ll dpu
[ 2 ] , dpv
[ 2 ] , dp
[ 2 ] ;
void C ( )
{ std
: : swap ( dpu
[ 0 ] , dpv
[ 0 ] ) ; std
: : swap ( dpu
[ 1 ] , dpv
[ 1 ] ) ;
}
void CP ( ll
* D
)
{ dp
[ 0 ] = D
[ 0 ] ; dp
[ 1 ] = D
[ 1 ] ;
}
ll
lca ( int u
, int v
)
{ if ( u
& 1 ) u
= ( u
+ 1 ) >> 1 , dpu
[ 0 ] = 0 , dpu
[ 1 ] = g
[ u
] ; else u
= ( u
+ 1 ) >> 1 , dpu
[ 0 ] = g
[ u
] , dpu
[ 1 ] = 0 ; if ( v
& 1 ) v
= ( v
+ 1 ) >> 1 , dpv
[ 0 ] = 0 , dpv
[ 1 ] = g
[ v
] ; else v
= ( v
+ 1 ) >> 1 , dpv
[ 0 ] = g
[ v
] , dpv
[ 1 ] = 0 ; if ( dep
[ u
] < dep
[ v
] ) std
: : swap ( u
, v
) , C ( ) ; const int DEP
= dep
[ u
] - dep
[ v
] ; for ( rg
int i
= 0 ; i
<= 20 ; i
++ ) if ( DEP
& ( 1 << i
) ) { CP ( dpu
) ; dpu
[ 0 ] = min ( dp
[ 0 ] + f
[ u
] [ i
] [ 0 ] [ 0 ] , dp
[ 1 ] + f
[ u
] [ i
] [ 1 ] [ 0 ] ) ; dpu
[ 1 ] = min ( dp
[ 0 ] + f
[ u
] [ i
] [ 0 ] [ 1 ] , dp
[ 1 ] + f
[ u
] [ i
] [ 1 ] [ 1 ] ) ; u
= p
[ u
] [ i
] ; mind ( dpu
[ 0 ] , dpu
[ 1 ] + g
[ u
] ) ; mind ( dpu
[ 1 ] , dpu
[ 0 ] + g
[ u
] ) ; } if ( u
== v
) return min ( dpu
[ 0 ] + dpv
[ 0 ] , dpu
[ 1 ] + dpv
[ 1 ] ) ; for ( rg
int i
= 20 ; i
>= 0 ; i
-- ) if ( p
[ u
] [ i
] != p
[ v
] [ i
] ) { CP ( dpu
) ; dpu
[ 0 ] = min ( dp
[ 0 ] + f
[ u
] [ i
] [ 0 ] [ 0 ] , dp
[ 1 ] + f
[ u
] [ i
] [ 1 ] [ 0 ] ) ; dpu
[ 1 ] = min ( dp
[ 0 ] + f
[ u
] [ i
] [ 0 ] [ 1 ] , dp
[ 1 ] + f
[ u
] [ i
] [ 1 ] [ 1 ] ) ; u
= p
[ u
] [ i
] ; mind ( dpu
[ 0 ] , dpu
[ 1 ] + g
[ u
] ) ; mind ( dpu
[ 1 ] , dpu
[ 0 ] + g
[ u
] ) ; CP ( dpv
) ; dpv
[ 0 ] = min ( dp
[ 0 ] + f
[ v
] [ i
] [ 0 ] [ 0 ] , dpv
[ 1 ] + f
[ v
] [ i
] [ 1 ] [ 0 ] ) ; dpv
[ 1 ] = min ( dp
[ 0 ] + f
[ v
] [ i
] [ 0 ] [ 1 ] , dpv
[ 1 ] + f
[ v
] [ i
] [ 1 ] [ 1 ] ) ; v
= p
[ v
] [ i
] ; mind ( dpv
[ 0 ] , dpv
[ 1 ] + g
[ v
] ) ; mind ( dpv
[ 1 ] , dpv
[ 0 ] + g
[ v
] ) ; } CP ( dpu
) ; dpu
[ 0 ] = min ( dp
[ 0 ] + f
[ u
] [ 0 ] [ 0 ] [ 0 ] , dp
[ 1 ] + f
[ u
] [ 0 ] [ 1 ] [ 0 ] ) ; dpu
[ 1 ] = min ( dp
[ 0 ] + f
[ u
] [ 0 ] [ 0 ] [ 1 ] , dp
[ 1 ] + f
[ u
] [ 0 ] [ 1 ] [ 1 ] ) ; u
= p
[ u
] [ 0 ] ; mind ( dpu
[ 0 ] , dpu
[ 1 ] + g
[ u
] ) ; mind ( dpu
[ 1 ] , dpu
[ 0 ] + g
[ u
] ) ; CP ( dpv
) ; dpv
[ 0 ] = min ( dp
[ 0 ] + f
[ v
] [ 0 ] [ 0 ] [ 0 ] , dpv
[ 1 ] + f
[ v
] [ 0 ] [ 1 ] [ 0 ] ) ; dpv
[ 1 ] = min ( dp
[ 0 ] + f
[ v
] [ 0 ] [ 0 ] [ 1 ] , dpv
[ 1 ] + f
[ v
] [ 0 ] [ 1 ] [ 1 ] ) ; v
= p
[ v
] [ 0 ] ; mind ( dpv
[ 0 ] , dpv
[ 1 ] + g
[ v
] ) ; mind ( dpv
[ 1 ] , dpv
[ 0 ] + g
[ v
] ) ; return min ( dpu
[ 0 ] + dpv
[ 0 ] , dpu
[ 1 ] + dpv
[ 1 ] ) ;
}
int main ( )
{ read ( n
) ; for ( rg
int i
= 1 ; i
<= n
; i
++ ) read ( g
[ i
] ) ; for ( rg
int i
= 1 ; i
< n
; i
++ ) { int u
, v
; ll w1
, w2
; read ( u
) , read ( v
) , read ( w1
) , read ( w2
) ; addb ( u
, v
, w1
, w2
) ; addb ( v
, u
, w1
, w2
) ; } dfs1 ( 1 , 0 ) ; p
[ 1 ] [ 0 ] = 1 , dfs2 ( 1 , 0 ) ; for ( rg
int j
= 1 ; j
<= 20 ; j
++ ) for ( rg
int i
= 1 ; i
<= n
; i
++ ) { const int P
= p
[ i
] [ j
- 1 ] ; p
[ i
] [ j
] = p
[ P
] [ j
- 1 ] ; const int T
= p
[ i
] [ j
] ; f
[ i
] [ j
] [ 0 ] [ 0 ] = min ( f
[ i
] [ j
- 1 ] [ 0 ] [ 0 ] + f
[ P
] [ j
- 1 ] [ 0 ] [ 0 ] , f
[ i
] [ j
- 1 ] [ 0 ] [ 1 ] + f
[ P
] [ j
- 1 ] [ 1 ] [ 0 ] ) ; f
[ i
] [ j
] [ 0 ] [ 1 ] = min ( f
[ i
] [ j
- 1 ] [ 0 ] [ 0 ] + f
[ P
] [ j
- 1 ] [ 0 ] [ 1 ] , f
[ i
] [ j
- 1 ] [ 0 ] [ 1 ] + f
[ P
] [ j
- 1 ] [ 1 ] [ 1 ] ) ; mind ( f
[ i
] [ j
] [ 0 ] [ 0 ] , f
[ i
] [ j
] [ 0 ] [ 1 ] + g
[ T
] ) ; mind ( f
[ i
] [ j
] [ 0 ] [ 1 ] , f
[ i
] [ j
] [ 0 ] [ 0 ] + g
[ T
] ) ; f
[ i
] [ j
] [ 1 ] [ 0 ] = min ( f
[ i
] [ j
- 1 ] [ 1 ] [ 0 ] + f
[ P
] [ j
- 1 ] [ 0 ] [ 0 ] , f
[ i
] [ j
- 1 ] [ 1 ] [ 1 ] + f
[ P
] [ j
- 1 ] [ 1 ] [ 0 ] ) ; f
[ i
] [ j
] [ 1 ] [ 1 ] = min ( f
[ i
] [ j
- 1 ] [ 1 ] [ 0 ] + f
[ P
] [ j
- 1 ] [ 0 ] [ 1 ] , f
[ i
] [ j
- 1 ] [ 1 ] [ 1 ] + f
[ P
] [ j
- 1 ] [ 1 ] [ 1 ] ) ; mind ( f
[ i
] [ j
] [ 1 ] [ 0 ] , f
[ i
] [ j
] [ 1 ] [ 1 ] + g
[ T
] ) ; mind ( f
[ i
] [ j
] [ 1 ] [ 1 ] , f
[ i
] [ j
] [ 1 ] [ 0 ] + g
[ T
] ) ; } read ( q
) ; while ( q
-- ) { int u
, v
; read ( u
) , read ( v
) ; print ( lca ( u
, v
) ) , putchar ( '\n' ) ; } return 0 ;
}
總結
以上是生活随笔 為你收集整理的codeforces contest 1140(D~G) 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。