生活随笔
收集整理的這篇文章主要介紹了
LuoguP4606 [SDOI2018]战略游戏
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
LuoguP4606 [SDOI2018]戰略游戲
題目描述
題目描述 省選臨近,放飛自我的小 QQ 無心刷題,于是慫恿小 CC 和他一起頹廢,玩起了一款戰略游戲。 這款戰略游戲的地圖由 nn 個城市以及 mm 條連接這些城市的雙向道路構成,并且從任意一個城市出發總能沿著道路走到任意其他城市。 現在小 CC 已經占領了其中至少兩個城市,小 QQ 可以摧毀一個小 CC 沒占領的城市,同時摧毀所有連接這個城市的道路。只要在摧毀這個城市之后能夠找到某兩個小 CC 占領的城市 uu 和 vv,使得從 uu 出發沿著道路無論如何都不能走到 vv,那么小 QQ 就能贏下這一局游戲。 小 QQ 和小 CC 一共進行了 qq 局游戲,每一局游戲會給出小 CC 占領的城市集合 SS,你需要幫小 QQ 數出有多少個城市在他摧毀之后能夠讓他贏下這一局游戲。
Solution
題意:給定一個nn n 個點mm m 條邊的無向圖,QQ Q 組詢問,每次給出一個點集{S}\{S\} { S } ,詢問有多少點被刪掉之后,點集{S}\{S\} { S } 會存在兩點不連通。
建廣義圓方樹。 建出圓方樹之后,讓兩個點u,vu,v u , v 不連通相當于刪掉了除了u,vu,v u , v 以外的某一個u?>vu->v u ? > v 路徑上的圓點。
設點集{S}={a1,a2,...,ak}\{S\}=\{a_1,a_2,...,a_k\} { S } = { a 1 ? , a 2 ? , . . . , a k ? } 點集中的點按dfsdfs d f s 序排序, 令相鄰點對(包括(a1,ak)(a_1,a_k) ( a 1 ? , a k ? ) )之間路徑的圓點數量和為ansans a n s 。 總的答案即為ans/2?k+[LCA(a1,ak)為圓點]ans/2-k+[LCA(a_1,a_k)為圓點] a n s / 2 ? k + [ L C A ( a 1 ? , a k ? ) 為 圓 點 ] 。
時間復雜度O(nlg?n)O(n\lg n) O ( n lg n ) 。 這題也可以用虛樹做,其實和上述方法差不多,只是實現方式不同。
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <cassert>
#include <string.h>
#define MP(A,B) make_pair(A,B)
#define PB(A) push_back(A)
#define SIZE(A) ((int)A.size())
#define LEN(A) ((int)A.length())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define fi first
#define se second using namespace std
; template < typename T
> inline bool upmin ( T
& x
, T y
) { return y
< x
? x
= y
, 1 : 0 ; }
template < typename T
> inline bool upmax ( T
& x
, T y
) { return x
< y
? x
= y
, 1 : 0 ; } typedef long long ll
;
typedef unsigned long long ull
;
typedef long double lod
;
typedef pair
< int , int > PR
;
typedef vector
< int > VI
; const lod eps
= 1e-11 ;
const lod pi
= acos ( - 1 ) ;
const int oo
= 1 << 30 ;
const ll loo
= 1ll << 62 ;
const int mods
= 1e9 + 7 ;
const int MAXN
= 200005 ;
const int INF
= 0x3f3f3f3f ;
inline int read ( )
{ int f
= 1 , x
= 0 ; char c
= getchar ( ) ; while ( c
< '0' || c
> '9' ) { if ( c
== '-' ) f
= - 1 ; c
= getchar ( ) ; } while ( c
>= '0' && c
<= '9' ) { x
= ( x
<< 3 ) + ( x
<< 1 ) + ( c
^ 48 ) ; c
= getchar ( ) ; } return x
* f
;
}
vector
< int > e
[ MAXN
] , E
[ MAXN
] ;
int n
, m
, dep
[ MAXN
] , Log
[ MAXN
] , a
[ MAXN
] ;
int dfn
[ MAXN
] , low
[ MAXN
] , stk
[ MAXN
] , fa
[ MAXN
] [ 20 ] , dist
[ MAXN
] , bnum
= 0 , top
= 0 , DFN
= 0 ;
int compare ( int x
, int y
) { return dfn
[ x
] < dfn
[ y
] ; }
void add_edge ( int u
, int v
) { E
[ u
] . PB ( v
) , E
[ v
] . PB ( u
) ; }
void tarjan ( int x
, int father
)
{ dfn
[ x
] = low
[ x
] = ++ DFN
; stk
[ ++ top
] = x
; for ( auto v
: e
[ x
] ) { if ( v
== father
) continue ; if ( dfn
[ v
] ) { low
[ x
] = min ( low
[ x
] , dfn
[ v
] ) ; continue ; } tarjan ( v
, x
) ; low
[ x
] = min ( low
[ x
] , low
[ v
] ) ; if ( low
[ v
] >= dfn
[ x
] ) { int y
; bnum
++ ; add_edge ( n
+ bnum
, x
) ; while ( y
= stk
[ top
-- ] ) { add_edge ( n
+ bnum
, y
) ; if ( v
== y
) break ; } } }
}
void dfs ( int x
, int father
)
{
dfn
[ x
] = ++ DFN
; dep
[ x
] = dep
[ father
] + 1 ; fa
[ x
] [ 0 ] = father
; for ( int i
= 1 ; i
<= Log
[ dep
[ x
] ] ; i
++ ) fa
[ x
] [ i
] = fa
[ fa
[ x
] [ i
- 1 ] ] [ i
- 1 ] ; for ( auto v
: E
[ x
] ) if ( v
!= father
) dist
[ v
] = dist
[ x
] + ( v
<= n
) , dfs ( v
, x
) ;
}
int get_LCA ( int x
, int y
)
{ if ( dep
[ x
] < dep
[ y
] ) swap ( x
, y
) ; for ( int i
= Log
[ dep
[ x
] ] ; i
>= 0 ; i
-- ) if ( dep
[ fa
[ x
] [ i
] ] >= dep
[ y
] ) x
= fa
[ x
] [ i
] ; if ( x
== y
) return x
; for ( int i
= Log
[ dep
[ x
] ] ; i
>= 0 ; i
-- ) if ( fa
[ x
] [ i
] != fa
[ y
] [ i
] ) x
= fa
[ x
] [ i
] , y
= fa
[ y
] [ i
] ; return fa
[ x
] [ 0 ] ;
}
int getans ( int x
, int y
)
{ int lca
= get_LCA ( x
, y
) ;
return dist
[ x
] + dist
[ y
] - dist
[ lca
] * 2 ;
}
void Init ( )
{ bnum
= 0 , top
= 0 , DFN
= 0 ; memset ( dist
, 0 , sizeof dist
) ; memset ( dfn
, 0 , sizeof dfn
) ; memset ( fa
, 0 , sizeof fa
) ; memset ( low
, 0 , sizeof low
) ; for ( int i
= 1 ; i
<= n
* 2 ; i
++ ) e
[ i
] . clear ( ) , E
[ i
] . clear ( ) ;
}
int main ( )
{
n
= read ( ) , m
= read ( ) ; int q
= read ( ) ; Init ( ) ; for ( int i
= 1 ; i
<= m
; i
++ ) { int u
= read ( ) , v
= read ( ) ; e
[ u
] . PB ( v
) ; e
[ v
] . PB ( u
) ; } tarjan ( 1 , 0 ) ; dep
[ 0 ] = - 1 , Log
[ 1 ] = 0 , dist
[ 1 ] = 0 ; for ( int i
= 2 ; i
<= n
* 2 ; i
++ ) Log
[ i
] = Log
[ i
>> 1 ] + 1 ; DFN
= 0 ; dfs ( 1 , 0 ) ; while ( q
-- ) { int k
= 2 ; a
[ 1 ] = read ( ) , a
[ 2 ] = read ( ) ; sort ( a
+ 1 , a
+ k
+ 1 , compare
) ; int ans
= getans ( a
[ 1 ] , a
[ k
] ) ; for ( int i
= 1 ; i
< k
; i
++ ) ans
+ = getans ( a
[ i
] , a
[ i
+ 1 ] ) ;
printf ( "%d\n" , ans
/ 2 - k
+ ( get_LCA ( a
[ 1 ] , a
[ k
] ) <= n
) ) ; } return 0 ;
}
總結
以上是生活随笔 為你收集整理的LuoguP4606 [SDOI2018]战略游戏 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。