Atcoder题解:Arc156_c
数据范围
我们考虑观察样例,发现样例都很小,而且
我们画一个链,发现链上的统配解就是倒过来。那么我们考虑普通的树,我们发现,普通的树比链的性质更强一些。
我们可以找到树的重心,将其分割成若干个子树。然后安排每个子树中的值到别的地方去。这样可以保证每个子树中的数都在别的子树中。
然后,我们需要按照拓扑序倒着往里填。例如,子树
如果树有两个重心,从重心边分成两棵树直接填充。
如果树只有一个重心,将所有分割出的子树从重心开始的
为什么重心当根就一定能匹配到只剩
因为是重心当根,就没有一个分出来的子树多于
每次找到最大的
int n,sz[5005],a,b,pa[5005];
vt<int>vv[5005];
inline void dfs(int x,int p){
sz[x]=1,pa[x]=p;
for(auto j:vv[x])if(j!=p){
dfs(j,x);sz[x]+=sz[j];
}
}
inline int cen(int x,int p){
for(auto j:vv[x])if(j!=p){
if(sz[j]*2>=n)return cen(j,x);
}
return x;
}
inline void dfss(int x,int p,vt<int>&v){
v.pb(x);
for(auto j:vv[x])if(j!=p){
dfss(j,x,v);
}
}
int ans[5005];
inline void solve1(int r){
vt<vt<int> >vs;
ans[r]=r;
for(auto j:vv[r]){
vt<int>v;
dfss(j,r,v);
vs.pb(v);
}
priority_queue<pii>pq;
rd(i,vs.size())pq.push({vs[i].size(),i});
while(pq.size()){
if(pq.size()==1){
int x=pq.top().second;pq.pop();
ans[vs[x].back()]=r;
ans[r]=vs[x].back();
break;
}
int x=pq.top().second;pq.pop();
int y=pq.top().second;pq.pop();
ans[vs[x].back()]=vs[y].back();
ans[vs[y].back()]=vs[x].back();
vs[x].pop_back();vs[y].pop_back();
if(vs[x].size())pq.push({vs[x].size(),x});
if(vs[y].size())pq.push({vs[y].size(),y});
}
rp(i,n)cout<<ans[i]<<" ";
cout<<endl;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n;
rp(i,n-1){
cin>>a>>b;
vv[a].pb(b);
vv[b].pb(a);
}
dfs(1,0);
int c1=cen(1,0),c2=c1;
bool flag=0;
if(n%2==0&&sz[c1]==n/2)c2=pa[c1],flag=1;
else if(n%2==0){
for(auto j:vv[c1])if(j!=pa[c1]&&sz[j]==n/2)c2=j,flag=1;
}
if(!flag){
solve1(c1);
return 0;
}
vt<int>v1,v2;
dfss(c1,c2,v1);
dfss(c2,c1,v2);
while(v1.size()){
ans[v1.back()]=v2.back();
ans[v2.back()]=v1.back();
v1.pop_back();v2.pop_back();
}
rp(i,n)cout<<ans[i]<<" ";
cout<<endl;
return 0;
}
//Crayan_r
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通