• ZROI#1013


    ZROI#1013

    ZROI#1013

    看起来以为是个 (Floyd) 传递闭包...
    一看数据范围,算了叭.这拿头过啊.

    一拿过来肯定缩点嘛.

    缩完点成为一个 (DAG) , 一般 (DAG) 先考虑考虑拓扑排序后再做.

    那么这个题怎么考虑拓扑呢?暂时还没有思路.

    但我们发现,如果我们有一条边 ((u,v)) , 那么 (v) 能达到的点, (u) 也一定能到达,因为 (u) 能到达 (v).

    如果我们把每个点能到的点视为一个二进制状态,那么显然有 (status_u = status_u | status_v)

    那么这是显然可以一路递推的,怎么递推呢?逆拓扑!

    总体思路呼之欲出了 (:)

    先缩点成为一个 (DAG) , 再对 (DAG) 做拓扑,以逆拓扑的顺序递推得到每个点的状态,查询直接查询对应位即可.

    但我们发现这样很不行,因为共有 (2 imes 10^5) 个点,每个点都要开这么大二进制状态,开出来人都没了.

    不如你每 (64) 个点压一个 (unsigned : long : long) 然后每个点只需要至多 (cfrac{n}{64})(ull) 就能存下,这样的空间就可以负担的起了.

    那么怎么实现呢?一个简单的方法是指针实现,开一个长度为 (1e8) 的内存池.

    对每个点及其所需空间顺次放入,用一个 (2 imes 10^5) 的指针数组指向每个点的起始位置,然后空出 (cfrac{n}{64}) 个位置留作第二维.

    这样,我们要在点 (u) 的状态中找一个点 (v) , 只需要把 (v) 对应的编号除以 (64) 得到它是在 (u) 之后的第几个位置,然后再和对应的位数取 (&) 即可.

    (Code:)

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <queue>
    #include <cmath>
    #include <ctime>
    #include <map>
    #include <set>
    #define MEM(x,y) memset ( x , y , sizeof ( x ) )
    #define rep(i,a,b) for (int i = (a) ; i <= (b) ; ++ i)
    #define per(i,a,b) for (int i = (a) ; i >= (b) ; -- i)
    #define pii pair < int , int >
    #define one first
    #define two second
    #define rint read<int>
    #define pb push_back
    #define db double
    #define ull unsigned long long
    #define lowbit(x) ( x & ( - x ) )
    
    using std::queue ;
    using std::set ;
    using std::pair ;
    using std::max ;
    using std::min ;
    using std::priority_queue ;
    using std::vector ;
    using std::swap ;
    using std::sort ;
    using std::unique ;
    using std::greater ;
    
    struct ios {
        inline char gc(){
            static const int IN_LEN=1<<18|1;
            static char buf[IN_LEN],*s,*t;
            return (s==t)&&(t=(s=buf)+fread(buf,1,IN_LEN,stdin)),s==t?-1:*s++;
        }
    
        template <typename _Tp> inline ios & operator >> (_Tp&x){
            static char ch,sgn; ch = gc(), sgn = 0;
            for(;!isdigit(ch);ch=gc()){if(ch==-1)return *this;sgn|=ch=='-';}
            for(x=0;isdigit(ch);ch=gc())x=x*10+(ch^'0');
            sgn&&(x=-x); return *this;
        }
    } io;
    
    const int N = 2e5 + 100 ;
    const int M = 1e8 + 100 ;
    const int E = 1e6 + 100 ;
    
    struct edge { int to , next ; } e[E] , G[E] ;
    
    queue < int > q ;
    int n , m , qs , ind[N] , dfn[N] , low[N] , top , L , head1[N] ;
    int idx[N] , siz[N] , cnt , tot , s[N] , tot1 , tot2 , head2[N] ;
    ull *now , *bit[N] , pool[M] ; bool ins[N] ;
    
    inline void tarjan (int cur) {
        s[++top] = cur ; ins[cur] = true ;
        dfn[cur] = low[cur] = ++ cnt ;
        for (int i = head1[cur] ; i ; i = e[i].next) {
            int k = e[i].to ;
            if ( ! dfn[k] ) {
                tarjan ( k ) ;
                low[cur] = std::min ( low[cur] , low[k] ) ;
            } else if ( ins[k] ) low[cur] = std::min ( low[cur] , dfn[k] ) ;
        }
        if ( low[cur] == dfn[cur] ) {
            while ( s[top+1] != cur ) {
                idx[s[top]] = tot ;
                ++ siz[tot] ;
                ins[s[top--]] = false ;
            }
            ++ tot ;
        }
        return ;
    }
    
    inline void update (int x , int y) { rep ( i , 0 , L - 1 ) bit[y][i] |= bit[x][i] ; return ; }
    
    inline void build (int u , int v ) {
        e[++tot1].next = head1[u] ;
        e[tot1].to = v ; head1[u] = tot1 ;
    }
    
    inline void _build (int u , int v ) {
        G[++tot2].next = head2[u] ;
        G[tot2].to = v ; head2[u] = tot2 ;
    }
    
    signed main (int argc , char * argv[]) {
        io >> n >> m >> qs ;
        rep ( i , 1 , m ) { int u , v ; io >> u >> v ; build ( u , v ) ; }
    
        rep ( i , 1 , n ) if ( ! dfn[i] ) tarjan ( i ) ;
        rep ( i , 1 , n ) for (int j = head1[i] ; j ; j = e[j].next) {
            int k = e[j].to ;
            if ( idx[i] != idx[k] ) { _build ( idx[k] , idx[i] ) ; ++ ind[idx[i]] ; }
        }
    
        now = pool ; L = ( tot + 63 ) / 64 ;
        rep ( i , 0 , tot - 1 ) {
            bit[i] = now ; now += L ;
            bit[i][i>>6] |= 1ull << ( i & 63 ) ;
        }
    
        while ( ! q.empty () ) q.pop () ;
        rep ( i , 0 , tot - 1 ) if ( ! ind[i] ) q.push ( i ) ;
        while ( ! q.empty () ) {
            int j = q.front () ; q.pop () ;
            for (int i = head2[j] ; i ; i = G[i].next) {
                int k = G[i].to ;
                -- ind[k] ; update ( j , k ) ;
                if ( ! ind[k] ) q.push ( k ) ;
            }
        }
    
        while ( qs -- )  {
            int u , v ; io >> u >> v ; u = idx[u] ; v = idx[v] ;
            if ( ( bit[u][v>>6] >> ( v & 63 ) ) & 1 ) puts ("Yes") ;
            else puts ("No") ;
        }
    
        system ("pause") ; return 0 ;
    }
    
  • 相关阅读:
    js事件列表
    PS快捷键
    去水印六种方法
    ps素材网站
    颜色搭配
    收集的各大官网的样式初始化
    目前公司用到的PC端和移动端的初始化样式
    CSS背景图拉伸自适应尺寸,全浏览器兼容代码
    队列的优化链式实现
    队列的优化顺序实现
  • 原文地址:https://www.cnblogs.com/Equinox-Flower/p/11716202.html
Copyright © 2020-2023  润新知