zoukankan      html  css  js  c++  java
  • [POI2013]POL-Polarization

    题目描述

    Everyone knew it would only be a matter of time. So what?

    Faced for years on, a peril becomes the every-day reality.

    It loses its meaning...

    Today the letter of the Bitotian char Bittard to the Byteotian king Byteasar was released to the public.

    Bitotia requested annexation of the whole Byteotia on pain of using the Bit Polarizing Magnet (BPM).

    If used, the BPM would make each and every road in Byteotia unidirectional.

    The enemy knows only too well that this could be a fatal blow to the minimalist Byteotian infrastructure - there is a unique way between each pair of towns.

    How badly can the BPM damage the Byteotian infrastructure?

    Determine the minimum and the maximum number of such pairs of towns that it will still be possible to travel from one of them to the other while observing the new roads orientation.

    给定一颗树,请给树边改成有向边,求连通的点对个数的最大最小值。点对连通,要么a能到达b,要么b能到达a。(n<=250000)

    输入输出格式

    输入格式:

    The first line of the standard input gives a single integer (), the number of towns in Byteotia.

    The lines that follow describe these roads.

    Each such line holds two integers, and (), which indicate that there is a direct road (still bidirectional at the moment) linking the towns no. and .

    In tests worth 60% of the total points, the additional constraint holds;moreover, in some of those, worth 30% of the total points, it even holds that .

    输出格式:

    Two integers should be printed to the first and only line of the standard output.

    The first number should be the minimum and the second - the maximum number of pairs of towns which could remain connected (though in one direction only) after the roads are polarized.

    输入输出样例

    输入样例#1:

    4
    1 2
    1 3
    1 4

    输出样例#1:

    3 5

    说明

    给定一颗树,请给树边改成有向边,求连通的点对个数的最大最小值。点对连通,要么a能到达b,要么b能到达a。(n<=250000)


    神奇的一道题反正我不会

    首先考虑最小值

    因为每连出去一条边至少会形成一个点对

    所以我们就考虑最小的情况

    因为是一颗树

    所以只有n-1条边,答案就是n-1

    具体连法就是第i-1层向第i层连的边与第i层向第i+1层的连的边的方向相反

    然后考虑最大值怎么求反正我不会证明

    最大值就是找打树的重心

    然后每个子树内部连边方向要相同

    然后尽量使得连向root的边的子树大小之和和root向外连出的边的子树大小之和相差小

    就感性理解一下反正我也不会证明

    然后把每个子树按照大小二进制拆分一下

    之后做一个背包就行了

    #include<queue>
    #include<bitset>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    # define LL long long
    const int M = 250005 ;
    const int INF = 2147483647 ;
    using namespace std ;
    inline int read() {
        char c = getchar() ; int x = 0 , w = 1 ;
        while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
        while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
        return x*w ;
    }
    
    int n , m ;
    struct E { int Nxt , to ; }edge[M<<1];
    int hea[M] , num ;
    inline void add_edge(int from , int to) {
        edge[++num].Nxt = hea[from] ; edge[num].to = to ; hea[from] = num ;
    }
    int size[M] , tmax , root , dep[M] , w[M<<1] ;
    LL Ans = 0 ;
    bitset< M > f ;
    void Getroot(int u , int father) {
        size[u] = 1 ; int Maxson = 0 ;
        for(int i = hea[u] ; i ; i = edge[i].Nxt) {
            int v = edge[i].to ;
            if(v == father) continue ;
            Getroot(v , u) ;
            size[u] += size[v] ; 
            Maxson = max(Maxson , size[v]) ;
        }
        Maxson = max(Maxson , n - size[u]) ;
        if(Maxson < tmax)  
            tmax = Maxson , root = u ;
    }
    int main() {
        n = read() ;
        for(int i = 1 , u , v ; i < n ; i ++) {
            u = read() , v = read() ;
            add_edge(u , v) ; add_edge(v , u) ;
        }
        tmax = n ;
        Getroot(1 , 0) ;
        Getroot(root , root) ;
        for(int i = 1 ; i <= n ; i ++) Ans += size[i] - 1 ;
        for(int i = hea[root] ; i ; i = edge[i].Nxt) {
            int v = edge[i].to ;
            ++w[size[v]] ;
        }
        for(int i = 1 ; i <= n ; i ++)
            while(w[i] > 2) 
    		    w[i] -= 2 , ++w[i<<1] ;
        f[0] = 1 ;
        for(int i = 1 ; i <= n ; i ++)
            while(w[i] -- )
                f |= f << i ;
        int x ;
        for(x = (n >> 1) ; !f[x] ; -- x) ;
        printf("%d %lld
    ",n - 1 , Ans + 1LL * x * (n - 1 - x)) ; 
        return 0 ;
    }
    
  • 相关阅读:
    【OI新闻】2016.10.06
    旧博客欢迎莅临
    【NYOJ42】一笔画问题
    LCIS最长公共上升子序列
    LIS最长上升子序列
    LCS最长公共子序列
    T2848 列车调度(二分或dp)
    二分图的最大匹配、完美匹配和匈牙利算法
    高精大水题
    最大0,1子矩阵
  • 原文地址:https://www.cnblogs.com/beretty/p/9594944.html
Copyright © 2011-2022 走看看