给定 n 个点, m 条边,每条边有边权。
有 q 个询问,每个询问询问用编号为 [li,ri] 之间的边构最小生成森林的权值和。
Data Constraint
n≤100,m≤100000,q≤15000
考虑对边建线段树,每个区间维护在最小生成森林上的边,显然最多只有 n−1 条边。
然后每次合并区间就直接用 Kruskal 重构。
#include
#include
#include
#include
#include
#include
using namespace std ;
#define N 100000 + 10
typedef long long ll ;
struct Edge {
int u , v , w ;
} E[N] ;
struct Tree {
vector < int > e ;
} T[4*N] ;
vector < int > tp ;
int fa[N] ;
int n , m , Q ;
int Get( int x ) { return fa[x] == x ? x : fa[x] = Get(fa[x]) ; }
void Merge( int l , int r ) {
tp.clear() ;
int h1 = 0 , h2 = 0 ;
int siz1 = T[l].e.size() , siz2 = T[r].e.size() ;
while ( h1 < siz1 || h2 < siz2 ) {
if ( h1 < siz1 && h2 < siz2 ) {
if ( E[T[l].e[h1]].w < E[T[r].e[h2]].w ) {
tp.push_back(T[l].e[h1]) ;
h1 ++ ;
} else {
tp.push_back(T[r].e[h2]) ;
h2 ++ ;
}
} else {
if ( h1 < siz1 ) {
tp.push_back(T[l].e[h1]) ;
h1 ++ ;
} else {
tp.push_back(T[r].e[h2]) ;
h2 ++ ;
}
}
}
}
void Kruskal( int now ) {
T[now].e.clear() ;
for (int i = 1 ; i <= n ; i ++ ) fa[i] = i ;
for (int i = 0 ; i < (signed)tp.size() ; i ++ ) {
int u = E[tp[i]].u , v = E[tp[i]].v ;
int fx = Get(u) ;
int fy = Get(v) ;
if ( fx != fy ) {
T[now].e.push_back(tp[i]) ;
fa[fx] = fy ;
}
}
}
void Build( int v , int l , int r ) {
if ( l == r ) {
T[v].e.push_back(l) ;
return ;
}
int mid = (l + r) >> 1 ;
Build( v + v , l , mid ) ;
Build( v + v + 1 , mid + 1 , r ) ;
Merge( v + v , v + v + 1 ) ;
Kruskal( v ) ;
}
void Search( int v , int l , int r , int x , int y ) {
if ( l == x && r == y ) {
Merge( 0 , v ) ;
Kruskal(0) ;
return ;
}
int mid = (l + r) >> 1 ;
if ( y <= mid ) Search( v + v , l , mid , x , y ) ;
else if ( x > mid ) Search( v + v + 1 , mid + 1 , r , x , y ) ;
else {
Search( v + v , l , mid , x , mid ) ;
Search( v + v + 1 , mid + 1 , r , mid + 1 , y ) ;
}
}
int main() {
freopen( "highway.in" , "r" , stdin ) ;
freopen( "highway.out" , "w" , stdout ) ;
scanf( "%d%d%d" , &n , &m , &Q ) ;
for (int i = 1 ; i <= m ; i ++ ) scanf( "%d%d%d" , &E[i].u , &E[i].v , &E[i].w ) ;
Build( 1 , 1 , m ) ;
for (int i = 1 ; i <= Q ; i ++ ) {
int l , r ;
scanf( "%d%d" , &l , &r ) ;
T[0].e.clear() ;
Search( 1 , 1 , m , l , r ) ;
ll ans = 0 ;
for (int i = 0 ; i < (signed)T[0].e.size() ; i ++ ) ans += E[T[0].e[i]].w ;
printf( "%lld\n" , ans ) ;
}
return 0 ;
}
以上.