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

*/

posted @ 2018-10-23 18:49  Pickupwin  阅读(179)  评论(0编辑  收藏  举报