ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF1039D You Are Given a Tree 根号分治、二分

2019-02-02 22:00:52  阅读:392  来源: 互联网

标签:Given cur 链长 复杂度 Tree sqrt fa 答案 根号


传送门


似乎直接做不太好做……

当你不会做的时候就可以考虑根号算法了(或许是这样的

可以发现:对于链长\(>\sqrt{n}\)的所有值,最多只有\(\sqrt{n}\)种答案。

所以对于链长\(\leq \sqrt{n}\)暴力计算

对于链长\(> \sqrt{n}\),因为答案相等的链长一定是连续的(即如果链长为\(i\)的答案和链长为\(j\)的答案相等,那么对于\(\forall k \in [i,j]\),链长为\(k\)的答案一定和这两者相等),所以可以二分。设当前计算到了\(j\),先计算\(j\)的答案,然后二分出答案与\(j\)相等的区间的右端点\(k\),那么\([j,k]\)的答案都相等,输出\(k-j+1\)次答案,然后继续计算\(k+1\)。

这个算法的复杂度是\(O(n\sqrt{n} + n\sqrt{n}logn)\)的,还不够优秀。

可以发现分治的两种计算的复杂度是不平均的,优化一下

设小于等于\(S\)时暴力,大于\(S\)时二分,那么复杂度为\(O(nS + n \frac{n}{S} logn)\),不难得到当\(S= \sqrt{nlogn}\)时有最优复杂度\(O(n\sqrt{nlogn})\)

注意:计算某一种链长的答案不要使用递归,应先处理好拓扑序然后递推,这样可以大大加快程序运行速度。

#include<bits/stdc++.h>
//This code is written by Itst
using namespace std;

inline int read(){
    int a = 0;
    char c = getchar();
    bool f = 0;
    while(!isdigit(c) && c != EOF){
        if(c == '-')
            f = 1;
        c = getchar();
    }
    if(c == EOF)
        exit(0);
    while(isdigit(c)){
        a = (a << 3) + (a << 1) + (c ^ '0');
        c = getchar();
    }
    return f ? -a : a;
}

const int MAXN = 1e5 + 10;
struct Edge{
    int end , upEd;
}Ed[MAXN << 1];
int head[MAXN] , cur[MAXN] , top[MAXN] , fa[MAXN] , N , T , cntEd , ans , ts;

inline void addEd(int a , int b){
    Ed[++cntEd].end = b;
    Ed[cntEd].upEd = head[a];
    head[a] = cntEd;
}

void input(){
    N = read();
    T = sqrt(N * log2(N));
    for(int i = 1 ; i < N ; ++i){
        int a = read() , b = read();
        addEd(a , b);
        addEd(b , a);
    }
}

void init(int x , int p){
    fa[x] = p;
    top[++ts] = x;
    for(int i = head[x] ; i ; i = Ed[i].upEd)
        if(Ed[i].end != p)
            init(Ed[i].end , x);
}

void solve(int q){
    ans = 0;
    fill(cur + 1 , cur + N + 1 , 1);
    for(int i = N ; i > 1 ; --i){
        int x = top[i];
        if(cur[fa[x]] != -1 && cur[x] != -1){
            if(cur[fa[x]] + cur[x] >= q){
                cur[fa[x]] = -1;
                ++ans;
            }
            else
                cur[fa[x]] = max(cur[fa[x]] , cur[x] + 1);
        }
    }
}

void work(){
    printf("%d\n" , N);
    for(int i = 2 ; i <= T ; ++i){
        solve(i);
        printf("%d\n" , ans);
    }
    for(int j = T + 1 ; j <= N ; ){
        solve(j);
        int cur = ans , L = j , R = N;
        while(L < R){
            int mid = (L + R + 1) >> 1;
            solve(mid);
            if(ans == cur)
                L = mid;
            else
                R = mid - 1;
        }
        while(j <= L){
            ++j;
            printf("%d\n" , cur);
        }
    }
}

int main(){
    input();
    init(1 , 0);
    work();
    return 0;
}

标签:Given,cur,链长,复杂度,Tree,sqrt,fa,答案,根号
来源: https://www.cnblogs.com/Itst/p/10349283.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有