5064. 友好城市

題目大意

給定n 個點m 條有向邊。
q 個詢問,每個詢問要求只用編號爲[li,ri] 的邊有多少對點可以相互到達。

Data Constraint
n150,m300000,q50000

題解

對於一個詢問,如果求出所有的強連通分量大小的話,問題就變得很簡單了。
用Kosaraju算法求強連通分量,然後就可以很方便的用bitset保存邊集優化轉移。
對於原邊集可以先分塊,然後維護一個邊集的ST表。每個詢問就可以很方便的取出對應的邊集了。

SRC

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<bitset>
#include<cmath>
using namespace std ;

#define N 300000 + 10
#define M 250 + 10
#define K 650 + 10
const int MAXN = 11 ;
struct Edge {
    int u , v ;
} E[N] ;

bitset < M > vis , tp ;
bitset < M > ret[M] , trans[M] , retrans[M] ;
bitset < M > f[2][K][MAXN][M] ;

int S[M] , Tab[N] ;
int Belong[N] ;
int n , m , Q ;
int Size , Cnt , Block ;

void Merge( int type , int i1 , int i2 , int j ) {
    for (int x = 1 ; x <= n ; x ++ ) {
        if ( i2 > Cnt ) ret[x] = f[type][i1][j][x] ;
        else ret[x] = f[type][i1][j][x] | f[type][i2][j][x] ;
    }
}

void Get( int l , int r ) {
    int k = Tab[r-l+1] ;
    Merge( 0 , l , r - (1 << k) + 1 , k ) ;
    for (int x = 1 ; x <= n ; x ++ ) trans[x] = ret[x] ;
    Merge( 1 , l , r - (1 << k) + 1 , k ) ;
    for (int x = 1 ; x <= n ; x ++ ) retrans[x] = ret[x] ;
}

void DFS( int x ) {
    vis[x] = 0 ;
    while ( 1 ) {
        tp = trans[x] & vis ;
        if ( !tp.any() ) break ;
        int Son = tp._Find_next(-1) ;
        DFS( Son ) ;
    }
    S[++S[0]] = x ;
}

void ReDFS( int x ) {
    vis[x] = 0 ;
    Size ++ ;
    while ( 1 ) {
        tp = retrans[x] & vis ;
        if ( !tp.any() ) break ;
        int Son = tp._Find_next(-1) ;
        ReDFS( Son ) ;
    }
}

int main() {
    freopen( "friend.in" , "r" , stdin ) ;
    freopen( "friend.out" , "w" , stdout ) ;
    scanf( "%d%d%d" , &n , &m , &Q ) ;
    Block = sqrt(m) ;
    for (int i = 1 ; i <= m ; i ++ ) {
        Belong[i] = i / Block + ( i % Block != 0 ) ;
        scanf( "%d%d" , &E[i].u , &E[i].v ) ;
    }
    Cnt = Belong[m] ;
    Tab[1] = 0 ;
    for (int i = 2 ; i <= Cnt ; i ++ ) Tab[i] = Tab[i/2] + 1 ;
    for (int i = 1 ; i <= Cnt ; i ++ ) {
        for (int j = (i - 1) * Block + 1 ; j <= i * Block ; j ++ ) {
            f[0][i][0][E[j].u][E[j].v] = 1 ;
            f[1][i][0][E[j].v][E[j].u] = 1 ;
        }
    }
    for (int type = 0 ; type <= 1 ; type ++ ) {
        for (int j = 1 ; j < MAXN ; j ++ ) {
            for (int i = 1 ; i <= Cnt ; i ++ ) {
                Merge( type , i , i + (1 << (j - 1)) , j - 1 ) ;
                for (int x = 1 ; x <= n ; x ++ ) f[type][i][j][x] = ret[x] ;
            }
        }
    }
    for (int i = 1 ; i <= Q ; i ++ ) {
        int l , r ;
        scanf( "%d%d" , &l , &r ) ;
        if ( Belong[l] != Belong[r] ) {
            for (int x = 1 ; x <= n ; x ++ ) trans[x].reset() , retrans[x].reset() ;
            int lx = Belong[l-1] != Belong[l] ? Belong[l] : Belong[l] + 1 ;
            int rx = Belong[r+1] != Belong[r] ? Belong[r] : Belong[r] - 1 ;
            if ( lx <= rx ) Get( lx , rx ) ;
            for (int j = l ; j <= (lx - 1) * Block ; j ++ ) {
                trans[E[j].u][E[j].v] = 1 ;
                retrans[E[j].v][E[j].u] = 1 ;
            }
            for (int j = rx * Block + 1 ; j <= r ; j ++ ) {
                trans[E[j].u][E[j].v] = 1 ;
                retrans[E[j].v][E[j].u] = 1 ;
            }
        } else {
            for (int x = 1 ; x <= n ; x ++ ) trans[x].reset() , retrans[x].reset() ;
            for (int j = l ; j <= r ; j ++ ) {
                trans[E[j].u][E[j].v] = 1 ;
                retrans[E[j].v][E[j].u] = 1 ;
            }
        }
        S[0] = 0 ;
        vis.set() ;
        for (int x = 1 ; x <= n ; x ++ ) {
            if ( vis[x] == 0 ) continue ;
            DFS(x) ;
        }
        vis.set() ;
        int ans = 0 ;
        while ( S[0] ) {
            if ( vis[S[S[0]]] == 0 ) { S[0] -- ; continue ; }
            Size = 0 ;
            ReDFS( S[S[0]] ) ;
            ans += Size * (Size - 1) / 2 ;
            S[0] -- ;
        }
        printf( "%d\n" , ans ) ;
    }
    return 0 ;
}

以上.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章