zoukankan      html  css  js  c++  java
  • ZROI#961

    ZROI#961

    很诡异地一道题,你看他问的是是否存在距离(din [dist,1.1dist])的路径.
    你想一下这个(1.1)是个啥.好像不知道,先考虑暴力叭.
    暴力你就(bfs),让点重复入队就好了,每个点维护一个(set),查询直接(lower\_bound)即可.
    (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 X first
    #define Y second
    #define rint read<int>
    #define int long long
    #define pb push_back
    
    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 ;
    
    template < class T >
        inline T read () {
            T x = 0 , f = 1 ; char ch = getchar () ;
            while ( ch < '0' || ch > '9' ) {
                if ( ch == '-' ) f = - 1 ;
                ch = getchar () ;
            }
           while ( ch >= '0' && ch <= '9' ) {
                x = ( x << 3 ) + ( x << 1 ) + ( ch - 48 ) ;
                ch = getchar () ;
           }
       return f * x ;
    }
    
    const int N = 2e5 + 100 ;
    
    struct edge { int to , next ; double data ; } e[N<<1] ;
    
    set < double > p[N] ;
    int n , m , Q , tot , head[N] ;
    double dis[N] ;
    bool vis[N] ;
    
    inline void build (int u , int v , double w) {
        e[++tot].next = head[u] ; e[tot].to = v ;
        e[tot].data = w ; head[u] = tot ; return;
    }
    
    queue < int > q ;
    inline void bfs (int cur) {
        vis[cur] = true ; q.push ( cur ) ;
        dis[cur] = 0 ; p[cur].insert ( dis[cur] ) ;
        while ( ! q.empty () ) {
            int j = q.front () ; q.pop () ; vis[j] = false ;
            for (int i = head[j] ; i ; i = e[i].next) {
                int k = e[i].to ;
                for (auto it : p[j]) {
                    double dist = it + e[i].data ;
                    if ( p[k].find ( dist ) == p[k].end () ) {
                        if ( ! vis[k] ) { q.push ( k ) ; vis[k] = true ; }
                        p[k].insert ( dist ) ;
                    }
                }
            }
        }
        return ;
    }
    
    signed main (int argc , char * argv[]) {
        n = rint () ; m = rint () ; Q = rint () ;
        rep ( i , 1 , m ) {
            int u = rint () , v = rint () , w = rint () ;
            build ( u , v , w ) ;
        }
        bfs ( 1 ) ;
        while ( Q -- ) {
            int k = rint () ; double dist ;
            scanf ("%lf" , & dist ) ;
            auto pos = p[k].lower_bound ( dist ) ;
            if ( pos == p[k].end () ) puts ("NO") ;
            else if ( *pos <= dist * 1.1 ) puts ("YES") ;
            else puts ("NO") ;
        }
        return 0 ;
    }
    

    然后我们发现,这个玩意儿的瓶颈在于转移的时候状态太多了.
    然后我们考虑优化这个东西.
    我们发现,如果说有三个距离(x,y,z)满足以下条件:

    [cfrac{z}{1.1}<x<y<z ]

    那么(y)就是没用的,显然答案的存在性不会因为缺少(y)而改变.
    于是我们每次合并两个距离集合(即上述代码的转移,本质是两个距离集合的合并)就可以把这些(y)踢掉,使用类似于归并排序的思路即可解决.
    这样你可能会认为还是会(TLE),但实际上它的复杂度是对的,为什么呢?
    因为(1.1^{450})远远大于了所有权值的总和(10^{18}),也就是说一个点最多同时有(450)个状态被保留.
    每次合并就是(Theta(450))的,查询随意,怎么搞都能过.
    (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 int long long
    #define pb push_back
    #define db double
    
    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 ;
    using std::lower_bound ;
    
    template < class T >
        inline T read () {
            T x = 0 , f = 1 ; char ch = getchar () ;
            while ( ch < '0' || ch > '9' ) {
                if ( ch == '-' ) f = - 1 ;
                ch = getchar () ;
            }
           while ( ch >= '0' && ch <= '9' ) {
                x = ( x << 3 ) + ( x << 1 ) + ( ch - 48 ) ;
                ch = getchar () ;
           }
       return f * x ;
    }
    
    const int N = 2e5 + 100 ;
    const int M = 477 ;
    struct edge { int to , next ; double data ; } e[N] ;
    queue < int > q ; double tmp[N] , dis[N][M] ;
    int n , m , Q , tot , head[N] , cnt[N] , deg[N] ;
    
    inline void build (int u , int v , double w) {
        e[++tot].next = head[u] ; e[tot].to = v ;
        e[tot].data = w ; head[u] = tot ; return;
    }
    
    inline void merge (int x , int y , double val) { // 从 x 到 y
        int l = 1 , r = 1 , now = 0 ;
        while ( l <= cnt[x] && r <= cnt[y] ) {
            double cur = dis[x][l] + val ;
            if ( cur < dis[y][r] ) {
                while ( now >= 2 && (db)cur <= (db)tmp[now-1] * 1.1 && cur >= tmp[now] ) -- now ;
                tmp[++now] = cur ; ++ l ;
            } else {
                while ( now >= 2 && (db)dis[y][r] <= (db)tmp[now-1] * 1.1 && dis[y][r] >= tmp[now] ) -- now ;
                tmp[++now] = dis[y][r] ; ++ r ;
            }
        }
        while ( l <= cnt[x] ) {
            double cur = dis[x][l] + val ;
            while ( now >= 2 && (db)cur <= (db)tmp[now-1] * 1.1 && cur >= tmp[now] ) -- now ;
            tmp[++now] = cur ; ++ l ;
        }
        while ( r <= cnt[y] ) {
            while ( now >= 2 && (db)dis[y][r] <= (db)tmp[now-1] * 1.1 && dis[y][r] >= tmp[now] ) -- now ;
            tmp[++now] = dis[y][r] ; ++ r ;
        }
        rep ( i , 1 , now ) dis[y][i] = tmp[i] ;
        cnt[y] = now ; return ;
    }
    
    inline void SPFA (int cur) {
    	rep ( i , 1 , n ) if ( ! deg[i] ) q.push ( i ) ;
        ++ cnt[cur] ; dis[cur][cnt[cur]] = 0.0 ;
        while ( ! q.empty () ) {
            int j = q.front () ; q.pop () ;
            for (int i = head[j] ; i ; i = e[i].next) {
                int k = e[i].to ; -- deg[k] ;
                merge ( j , k , e[i].data ) ;
                if ( ! deg[k] ) q.push ( k ) ;
            }
        }
        return ;
    }
    
    signed main (int argc , char * argv[]) {
        n = rint () ; m = rint () ; Q = rint () ;
        rep ( i , 1 , m ) {
            int u = rint () , v = rint () ; db w ; scanf ("%lf" , & w ) ;
            build ( u , v , w ) ; ++ deg[v] ;
        }
        SPFA ( 1 ) ;
        while ( Q -- ) {
            int k = rint () , dist = rint () ;
            int pos = lower_bound ( dis[k] + 1 , dis[k] + cnt[k] + 1 , dist ) - dis[k] ;
            if ( (db)dis[k][pos] > (db)1.1 * dist || pos == cnt[k] + 1 ) puts ("NO") ; else puts ("YES") ;
        }
        return 0 ;
    }
    
    May you return with a young heart after years of fighting.
  • 相关阅读:
    SqlServer Alwayson 搭建排错记录(一)
    SqlServer图形数据库初体验
    SqlServer报错:主体“dbo”不存在
    IIS重叠回收
    No module named 'revoscalepy'问题解决
    SqlServer查询文件组被占用情况
    SqlServer作业指定目标服务器
    [持续更新]UnsatisfiedLinkError常见问题及解决方案
    Android加载SO库UnsatisfiedLinkError错误的原因及解决方案
    _set_invalid_parameter_handler异常处理函数
  • 原文地址:https://www.cnblogs.com/Equinox-Flower/p/11536113.html
Copyright © 2011-2022 走看看