题目链接
https://codeforces.com/problemset/problem/708/C
题意
给一棵树,你有一次删去任一边,加上任一边(必须维持树结构)的操作机会,问每个点是否可以经过(当然也可以不经过)操作成为重心。
思路
想复杂了
先复习下重心,定义就是题中的,最大子树不超过N/2。重心最少一个,最多为相连两个,所有节点到重心距离和最小。
我们考虑两个重心情况,对不是重心的任一点,我们可以断开重心间边,选择这个点和另一侧重心相连,显然全有解
考虑单个重心情况,容易想到以下贪心做法:选择重心为根跑一下子树结点数,检验当前点时,选取重心不含当前点的最大子树,将其移向自己,检验答案即可。且若一点不可选取,则其重心为根意义下子树都不可选取。
(这边bb下我本来做法,我是列出重心相连子树数组,每次二分的找满足条件的点,属实是想复杂了,好在是过了,不过硬做了一上午,哎,还是菜)
(本质上还是没想清楚移动子树这个操作,分析问题要看本质啊!)
代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
//#define double long double
using namespace std;
typedef long long ll;
const int maxn=400500;
const int inf=0x3f3f3f3f;
int n,m;
int sz[maxn],weight[maxn],centroid[2];
int val[maxn],from[maxn];
int rt,big1,big2;
vector<int>e[maxn];
bool ok[maxn];
vector<int>sortV;
//处理重心
void GetCentroid(int x,int fa){
sz[x]=1;
weight[x]=0;
for(auto y:e[x]){
if(y!=fa){
GetCentroid(y,x);
sz[x]+=sz[y];
weight[x]=max(weight[x],sz[y]);
}
}
weight[x]=max(weight[x],n-sz[x]);
if(weight[x]<=n/2){
centroid[centroid[0]!=0]=x;
}
}
//处理子树权
void getVa(int x,int fa){
val[x]=1;
for(auto y:e[x]){
if(y==fa) continue;
getVa(y,x);
val[x]+=val[y];
}
}
//处理每个点对应根节点子树编号
void find_from(int x,int fa,int rt){
from[x]=rt;
for(auto y:e[x]){
if(y==fa) continue;
find_from(y,x,rt);
}
}
bool cmp(int a,int b){
return val[a]<val[b];
}
//递归检验
void dffs(int x,int fa){
int li=((n-1)/2)+1-val[x];
if(big1<li) return ;
else if(val[from[x]]==big1&&big2<li) return ;
ok[x]=1;
for(auto y:e[x]){
if(y==fa) continue;
dffs(y,x);
}
}
void chck(){
rt=centroid[0];
getVa(rt,-1);
ok[rt]=1;
for(auto y:e[rt])
sortV.push_back(val[y]);
sort(sortV.begin(),sortV.end());
big1=sortV[sortV.size()-1];
big2=sortV[sortV.size()-2];
for(auto y:e[rt])
find_from(y,rt,y);
for(auto y:e[rt])
dffs(y,rt);
for(int i=1;i<=n;i++){
if(!ok[i]) cout<<'0';
else cout<<'1';
if(i!=n) cout<<' ';
}
cout<<endl;
}
int main(){
IOS
#ifndef ONLINE_JUDGE
freopen("IO\\in.txt","r",stdin);
freopen("IO\\out.txt","w",stdout);
#endif
int tn;
cin>>n;
for(int i=1;i<n;i++){
int u,v;
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
GetCentroid(1,-1);
if(n==2||n==3||centroid[1]){
for(int i=1;i<=n;i++){
cout<<1;
if(i!=n) cout<<' ';
}
cout<<endl;
}
else{
chck();
}
return 0;
}