BZOJ 2097 Exercise

二分一下答案长度
DP求直径
最长次长加起来爆了就把最长切了
明显提前切不优,没爆就不切
复杂度 \(O(nlog^2n)\)

#include <cstdio>
#include <vector>
#include <functional>
#include <algorithm>

using std::sort;
using std::vector;
using std::greater;

const int MAXN=100111;

int N, K;

struct Vert{
    int FE;
    int Len;
} V[MAXN];

struct Edge{
    int x, y, next;
} E[MAXN<<1];

int Ecnt;

void addE(int a, int b){
    ++Ecnt;
    E[Ecnt].x=a;E[Ecnt].y=b;E[Ecnt].next=V[a].FE;V[a].FE=Ecnt;
}

int Lim, Kc;

void DFS(int at, int f=0){
    vector<int> L;L.clear();
    for(int k=V[at].FE, to;k>0;k=E[k].next){
        to=E[k].y;
        if(to==f)   continue;
        DFS(to, at);
        L.push_back(V[to].Len+1);
    }
    L.push_back(0);L.push_back(0);
    sort(L.begin(), L.end(), greater<int>());
    for(unsigned int i=0U;(i+1U)<L.size();i+=1U){
        if(L[i]+L[i+1U]>Lim)
            ++Kc;
        else{
            V[at].Len=L[i];
            break;
        }
    }
}

bool Test(int l){
    Lim=l;Kc=0;
    DFS(1);
    return (Kc<=K);
}

int main(){
    
    scanf("%d%d", &N, &K);
    
    for(int i=1, a, b;i<N;++i){
        scanf("%d%d", &a, &b);
        addE(a, b);addE(b, a);
    }
    
    int Left=0, Right=N, Mid;
    while(Left<Right){
        Mid=(Left+Right)>>1;
        if(Test(Mid)) Right=Mid;
        else    Left=Mid+1;
    }
    Mid=(Left+Right)>>1;
    
    printf("%d\n", Mid);
    
    return 0;
}

/*
7 2
6 7
3 4
6 5
1 2
3 2
4 5

2

*/

猜你喜欢

转载自www.cnblogs.com/Pickupwin/p/BZOJ2097.html