#6042. 「雅礼集训 2017 Day7」跳蚤王国的宰相
内存限制:1024 MiB
时间限制:2000 ms
标准输入输出
题目类型:传统
评测方式:文本比较
上传者: 匿名
题目描述
输入格式
输出格式
样例
数据范围与提示
首先很容易发现这个点被选中时没有任意一个儿子的siz>n/2
除的话涉及取整,可能表意错误,我们用乘:siz*2>n
然后,你就发现重心满足性质。
然后,你就发现每个点最多只有一个儿子会破坏性质,
然后,你就发现那个儿子一定是在那个点往重心的位置,
设那个点为A,重心为B
你会发现,A到B之间的边都不需要割,只需要割B周围的边(因为B的儿子的siz都满足条件),
然后,就在B旁边选最少的边使其满足条件。贪心即可。
然后,你会发现,这些方案大多数是差不多的,一般只会相差一个或0个。
然后,用你的脑子优化程序就AC了!
但是为什么会想到重心呢?
因为经验。
为什么在这个科学主义的社会仍有这样经验主义的封建残余呢?
因为这是人类的智慧。
ACcode:
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<vector>
#define maxn 1000005
using namespace std;
int n,siz[maxn],esiz[maxn],ans[maxn];
vector<int>g[maxn];
int sum=0,cnt=0;
int rt,Min;
void dfs(int now,int ff,int tsz){
int Max=0;
siz[now]=1;
for(int i=0;i<esiz[now];i++)
if(g[now][i]!=ff){
dfs(g[now][i],now,tsz);
siz[now]+=siz[g[now][i]];
Max=max(Max,siz[g[now][i]]);
}
Max=max(Max,tsz-siz[now]);
if(Max<Min){
rt=now;
Min=Max;
}
}
int Gert(int now,int tsz){
Min=0x3f3f3f3f;
dfs(now,-1,tsz);
return rt;
}
bool cmp(const int &a,const int &b){
return siz[a]>siz[b];
}
void ser(int now,int ff,int usd){
ans[now]=cnt+( (n-usd-siz[now])*2 > n);
for(int i=0;i<esiz[now];i++)
if(g[now][i]!=ff)
ser(g[now][i],now,usd);
}
int main(){
int u,v;
scanf("%d",&n);
for(int i=1;i<n;i++){
scanf("%d %d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
esiz[u]++,esiz[v]++;
}
int A=Gert(1,n);
dfs(A,-1,0);
sort(g[A].begin(),g[A].end(),cmp);
for(int i=0;i<esiz[A];i++){
sum=(sum+siz[g[A][i]]);
if((sum<<1)>=n) break;
cnt++;//本来答案应该是cnt或cnt-1的,故意少加一,在解决函数中加一
}
for(int i=0;i<esiz[A];i++)
ser(g[A][i],A,sum-max(siz[g[A][i]],siz[g[A][cnt]]));//当前子树未被割,于是max会选siz[g[A][cnt]],被割了,就会选siz[g[A][i]]
for(int i=1;i<=n;i++)
printf("%d\n",ans[i]);
}