description
solution
一道非常好的二分+贪心题目。
第一问就是\(\frac{\sum_u(deg[u]-1)}{2}+1\)。
第二问需要在方案最优的情况下最长链最短,考虑二分。
那么自底向上地考虑每个子树中的节点,
我们发现每个节点要产生最优方案,一定是考虑选择自己伸向父亲的链和合并儿子伸向自己的链。
于是我们把所有儿子伸向自己的链长排序,
那么我们需要在合并的链长不超过二分答案的情况下使得伸向父亲的链长最小。
由于伸向父亲链长越小合并答案越不容易满足,因此考虑二分这个伸向父亲的链长。
总复杂度为\(O(nlog^2n)\)
Code
#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cstring>
#include<complex>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<ctime>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define Cpy(x,y) memcpy(x,y,sizeof(x))
#define Set(x,y) memset(x,y,sizeof(x))
#define FILE "a"
#define mp make_pair
#define pb push_back
#define RG register
#define il inline
using namespace std;
typedef unsigned long long ull;
typedef vector<int>VI;
typedef long long ll;
typedef double dd;
const dd eps=1e-7;
const int N=300010;
const int M=1000010;
const int inf=2147483647;
const ll INF=1e18+1;
const ll P=100000;
il ll read(){
RG ll data=0,w=1;RG char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
return data*w;
}
il void file(){
srand(time(NULL)+rand());
freopen(FILE".in","r",stdin);
freopen(FILE".out","w",stdout);
}
int n;
int head[N],nxt[N<<1],to[N<<1],cnt,d[N];
int c,flg;
int f[N];VI L[N];
il int pick(int k,int fb){
RG int len=L[k].size(),mx=0;
if(!((len&1)^(fb==-1))){if(fb==len-1)len--;mx=L[k][len-1];len--;}
for(RG int i=0,j=len-1;i<=j;i++,j--){
if(i==fb)i++;if(j==fb)j--;if(i>j)break;
mx=max(mx,L[k][i]+L[k][j]);
}
return mx;
}
void dfs(int u,int ff){
f[u]=0;L[u].clear();
for(RG int i=head[u];i;i=nxt[i]){
RG int v=to[i];if(v==ff)continue;
dfs(v,u);if(!flg)return;
L[u].push_back(f[v]+1);
}
sort(L[u].begin(),L[u].end());
if(!ff){if(pick(u,-1)>c){flg=0;return;}return;}
else if((d[u]&1)&&pick(u,-1)<=c)return;
RG int l=0,r=L[u].size()-1,mid;
while(l<=r){
mid=(l+r)>>1;
if(pick(u,mid)<=c)f[u]=L[u][mid],r=mid-1;
else l=mid+1;
}
if(!f[u]){flg=0;return;}
}
il bool check(int w){c=w;flg=1;dfs(1,0);return flg;}
int main()
{
n=read();
for(RG int i=1,u,v;i<n;i++){
u=read();v=read();d[u]++;d[v]++;
to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
to[++cnt]=u;nxt[cnt]=head[v];head[v]=cnt;
}
RG int l=1,r=n-1,mid,ans=n,ret=0;
for(RG int i=1;i<=n;i++)ret+=(d[i]-1)/2;ret++;
while(l<=r){
mid=((l+r)>>1);
if(check(mid))ans=mid,r=mid-1;
else l=mid+1;
}
printf("%d %d\n",ret,ans);
return 0;
}