第一问可以dp,第二问可以二分答案,然后再dp一遍判断
dp的时候记录最少用多少路径以及连着父亲的路径多长即可
把所有儿子按长度排序后尽量合并
复杂度n log^2 n
数据比较水,所以瞎几把合并一下就可以过了
#include<iostream>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<cstdlib>
#include<cstdio>
#include<map>
#include<bitset>
#include<set>
#include<stack>
#include<vector>
#include<queue>
using namespace std;
#define MAXN 10010
#define MAXM 1010
#define ll long long
#define eps 1e-8
#define MOD 1000000007
#define INF 1000000000
struct vec{
int to;
int fro;
};
struct data{
int c;
int l;
data(){
}
data(int _c,int _l){
c=_c;
l=_l;
}
friend bool operator <(data x,data y){
return x.c!=y.c?x.c<y.c:x.l<y.l;
}
};
vec mp[MAXN*2];
int tai[MAXN],cnt;
data f[MAXN];
vector<int>ps[MAXN];
int n;
int ANS,ans;
int lim;
inline void be(int x,int y){
mp[++cnt].to=y;
mp[cnt].fro=tai[x];
tai[x]=cnt;
}
inline void bde(int x,int y){
be(x,y);
be(y,x);
}
void dp(int x,int F){
int i,y;
bool flag=0;
int mn=INF,mn1=INF,mn2=INF;
f[x].c=0;
f[x].l=0;
ps[x].clear();
for(i=tai[x];i;i=mp[i].fro){
y=mp[i].to;
if(y!=F){
flag=1;
dp(y,x);
ps[x].push_back(f[y].l);
f[x].c+=f[y].c;
}
}
if(!flag){
f[x].c=1;
f[x].l=1;
return ;
}
sort(ps[x].begin(),ps[x].end());
int r=ps[x].size()-1;
data tmp=f[x];
for(i=1;i<r;i++){
while(r>i&&ps[x][i]+ps[x][r]>lim){
r--;
}
if(r>i){
tmp.c--;
r--;
}
}
if(x!=1){
tmp.c++;
tmp.l=1;
if(ps[x][0]+1<=lim){
tmp.c--;
tmp.l=ps[x][0]+1;
}
}
for(i=0,r=ps[x].size()-1;i<r;i++){
while(r>i&&ps[x][i]+ps[x][r]>lim){
r--;
}
if(r>i){
f[x].c--;
ps[x][i]=-1;
ps[x][r]=-1;
r--;
}
}
if(x!=1){
f[x].c++;
f[x].l=1;
for(i=0;i<ps[x].size();i++){
if(ps[x][i]!=-1&&ps[x][i]+1<=lim){
f[x].c--;
f[x].l=ps[x][i]+1;
break;
}
}
}
f[x]=min(f[x],tmp);
}
int main(){
int i,x,y;
scanf("%d",&n);
for(i=1;i<n;i++){
scanf("%d%d",&x,&y);
bde(x,y);
}
lim=n;
dp(1,0);
ANS=f[1].c;
//*
int l=1,r=n;
while(l<=r){
int mid=l+r>>1;
lim=mid;
dp(1,0);
if(f[1].c==ANS){
ans=mid;
r=mid-1;
}else{
l=mid+1;
}
}
//*/
printf("%d %d\n",ANS,ans);
return 0;
}
/*
9
7 8
4 5
5 6
1 2
3 2
9 8
2 5
5 8
*/