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 ;
    }
    
  • 相关阅读:
    SQL DATE_SUB 函数用法
    MySQL中concat函数(连接字符串)
    Mysql命令
    PHP 数字转汉字函数
    php 递归的生成目录函数
    我的SublimeText配置
    常见HTTP状态200,304,403,404,503
    鞋子特大号歌词
    去掉iframe白色背景方法
    php 空格无法替换,utf-8空格惹的祸
  • 原文地址:https://www.cnblogs.com/beretty/p/9594944.html
Copyright © 2011-2022 走看看