zoukankan      html  css  js  c++  java
  • BZOJ5188: [Usaco2018 Jan]MooTube 并查集+离线处理

    BZOJ又不给题面...

    Luogu的翻译看不下去...

    题意简述

    有一个$n$个节点的树,边有权值,定义两个节点之间的距离为两点之间的路径上的最小边权

    给你$Q$个询问,问你与点$v$的距离超过$k$的点有多少个

    $n,Q<=100000$

    题解

    很妙的做法。

    并查集+离线

    显然可以把询问离线,按K值排序

    处理距离的话可以使用并查集,并不需要带权,只需要把边也按权值排序,用并查集维护。

    具体做法:对每个点维护一个$siz$数组表示与它联通的节点数目,用类似双指针的方法把符合规则的边的两端点并起来,$siz$也顺便并起来就好

    对于每个询问的答案就是把大于k的边并起来之后的$siz[v]-1$

    #include<set>
    #include<cstdio>
    #include<algorithm>
    
    #define ll long long
    #define inf 0x3f3f3f3f 
    #define il inline 
    
    namespace io {
    
        #define in(a) a=read()
        #define out(a) write(a)
        #define outn(a) out(a),putchar('
    ')
    
        #define I_int int 
        inline I_int read() {
            I_int x = 0 , f = 1 ; char c = getchar() ;
            while( c < '0' || c > '9' ) { if( c == '-' ) f = -1 ; c = getchar() ; } 
            while( c >= '0' && c <= '9' ) { x = x * 10 + c - '0' ; c = getchar() ; } 
            return x * f ;
        } 
        char F[ 200 ] ;
        inline void write( I_int x ) {
            I_int tmp = x > 0 ? x : -x ;
            if( x < 0 ) putchar( '-' ) ;
            int cnt = 0 ;
            while( tmp > 0 ) {
                F[ cnt ++ ] = tmp % 10 + '0' ;
                tmp /= 10 ;
            }
            while( cnt > 0 ) putchar( F[ -- cnt ] ) ;
        }
        #undef I_int
    
    }
    using namespace io ;
    
    using namespace std ;
    
    #define N 100010
    
    struct edge {
        int u , v , w ;
        bool operator < ( const edge &x ) const {
            return w > x.w ;
        }
    } a[ N ] ;
    
    struct node {
        int k , v , id ;
        bool operator < ( const node &x ) const {
            return k > x.k ;
        }
    } b[ N ] ;
    
    int f[ N ] , siz[ N ] ;
    int n , m , ans[ N ] ;
    
    int find( int x ) {
        if( f[ x ] == x ) return x ;
        else return f[ x ] = find( f[ x ] ) ;
    }
    
    int main() {
        n = read() ; m = read() ;
        for( int i = 1 ; i < n ; i ++ ) {
            a[ i ] = (edge) { read() , read() , read() } ;
        }
        for( int i = 1 ; i <= m ; i ++ ) {
            b[ i ] = (node) { read() , read() , i } ;
        }
        sort( a + 1 , a + n + 1 ) ; sort( b + 1 , b + m + 1 ) ;
        int j = 1 ;
        for( int i = 1 ; i <= n ; i ++ ) siz[ i ] = 1 , f[ i ] = i ;
        for( int i = 1 ; i <= m ; i ++ ) {
            while( j < n && a[ j ].w >= b[ i ].k ) {
                int x = find( a[ j ].u ) , y = find( a[ j ].v ) ;
                if( x != y ) {
                    f[ y ] = x ;
                    siz[ x ] += siz[ y ] ;
                }
                j ++ ;
            }
            ans[ b[ i ].id ] = siz[ find( b[ i ].v ) ] - 1 ;
        }
        for( int i = 1 ; i <= m ; i ++ ) {
            printf( "%d
    " , ans[ i ] ) ;
        }
        return 0 ;
    }
  • 相关阅读:
    自己遇到的冲突及解决方案
    怎么解决代码冲突及切换分支
    程序员修养
    代码回退
    gitlab两种连接方式:ssh和http配置介绍
    gitlab创建项目及分支
    github,gitlab的区别
    代码托管有什么用
    新手搭建云服务器详细过程
    UNP学习笔记(第十一章 名字与地址转换)
  • 原文地址:https://www.cnblogs.com/henry-1202/p/BZOJ5188.html
Copyright © 2011-2022 走看看