题解 P7165 [COCI2020-2021#1] Papričice
1.题解 P7763 [COCI2016-2017#5] Ronald2.题解 P6497 [COCI2016-2017#2] Prosječni3.题解 P7537 [COCI2016-2017#4] Rima4.题解 P8017 [COCI2013-2014#4] UTRKA5.题解 P7751 [COCI2013-2014#2] PUTNIK6.题解 P7752 [COCI2013-2014#2] PALETA7.题解 P7586 [COCI2012-2013#1] SNAGA8.题解 P6485 [COCI2010-2011#4] PROSJEK9.题解 P6447 [COCI2010-2011#1] ŽABE10.题解P6677 [COCI2019-2020#2] Checker11.题解P8073 [COCI2009-2010#7] BAKICE12.题解P8084 [COCI2011-2012#4] BROJ13.题解P6370 [COCI2006-2007#6] KAMEN
14.题解 P7165 [COCI2020-2021#1] Papričice
15.题解 P9911 [COCI 2023/2024 #2] Kuglice16.题解 P6356 [COCI2007-2008#3] CUDAK17.题解 P7309 [COCI2018-2019#2] Kocka18.题解 P6548 [COCI2010-2011#2] IGRA19.题解 P6491 [COCI2010-2011#6] ABECEDA传送门。
题意
有一棵树,可以断掉
分析
我们观察两条边之间的关系,分类考虑:
- 两条边成祖孙关系。
- 两条边没有祖孙关系。
首先,我们肯定我们的大方向,固一动一(说起来为什么想到了数学题),先固定一条边,再在其他边中取得最适合的边,那这一条边,我们显然可以确定,这条边应当是平分剩余的连通块。
对于第一种。
想出来了两种方法。
第一种,从上往下,先固定上面(令这个节点为
时间复杂度:
inline void dfs(int now,int fath) { siz[now]=1,son[now]=0; for(auto to:lj[now]) { if(to==fath) continue; dfs(to,now); siz[now]+=siz[to]; if(siz[son[now]]<siz[to]) son[now]=to; } } inline void add(int now,int fath,int x) { se.insert(siz[now]); for(auto to:lj[now]) if(to!=fath&&to!=x) add(to,now,0); } inline void redfs(int now,int fath,int opt) { for(auto to:lj[now]) if(to!=fath&&to!=son[now]) redfs(to,now,0); if(son[now]) redfs(son[now],now,1); add(now,fath,son[now]); int A=n-siz[now]; auto it=se.upper_bound(siz[now]/2); if(it!=se.end()) MIN(A,*it); if(it!=se.begin()) it--,MIN(A,*it); if(it!=se.begin()) it--,MIN(A,*it); if(!opt) se.clear(); }
第二种,从下往上,维护到父亲的链上的节点数,那此时,我们的节点数应当尽量接近
inline void redfs(int now,int fath) { int A=siz[now]; auto it=se.upper_bound((n-siz[now])/2+siz[now]); if(it!=se.end()) MIN(A,(*it)-siz[now]); if(it!=se.begin()) it--,MIN(A,(*it)-siz[now]); if(it!=se.begin()) it--,MIN(A,(*it)-siz[now]); se.insert(siz[now]); for(auto to:lj[now]) if(to!=fath) redfs(to,now); se.erase(se.find(siz[now])); }
时间复杂度:
对于第二种。
我们只需要将我们跑完的节点加入 set 即可,最后尽量接近
inline void reredfs(int now,int fath) { int A=siz[now]; auto it=se.upper_bound((n-siz[now])/2); if(it!=se.end()) MIN(A,*it); if(it!=se.begin()) it--,MIN(A,*it); if(it!=se.begin()) it--,MIN(A,*it); for(auto to:lj[now]) if(to!=fath) reredfs(to,now); se.insert(siz[now]); }
于是就可以完美解决了。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战