CF911F Tree Destruction
题目链接:https://www.luogu.com.cn/problem/CF911F
solution:先求得树的直径,再求得在树的直径上的节点和不在树的直径上的节点。我们考虑优先删除不在直径上的节点,这样不会破坏树的直径,在删完了这些点之后再慢慢删直径上的点。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 2e5+10;
int n;
vector<int> vec[maxn];
int u,v,dis[maxn],on[maxn],fa[maxn];
void dfs1(int u)
{
for(auto v:vec[u])
{
if(dis[v]==-1)
{
dis[v]=dis[u]+1;
dfs1(v);
}
}
}
void dfs2(int now)
{
for(auto to:vec[now])
{
if(dis[to]>dis[now])
{
fa[to]=now;
dfs2(to);
on[now]=on[now]||on[to];//处理在直径上的点
}
}
}
int ans=0;
vector<array<int,3> >s;
void dfs3(int now,int rt)
{
for(auto to:vec[now])
{
if(dis[to]>dis[now])
{
dfs3(to,on[to]?to:rt);
//可以理解为直径是纵向的道路,不在直径上的是横向的道路
}
}
if(!on[now])
{
if(dis[now]>dis[now]+dis[v]-(dis[rt]<<1))
{
ans+=dis[now];
s.push_back({u,now});
}
else
{
ans+=dis[now]+dis[v]-(dis[rt]<<1);
s.push_back({v,now});
}
}
}
signed main()
{
scanf("%lld",&n);
for(int i=1;i<=n-1;i++)
{
int u,v;
scanf("%lld%lld",&u,&v);
vec[u].push_back(v);
vec[v].push_back(u);
}
memset(dis,-1,sizeof(dis));
dfs1(1);
u=1;
for(int i=1;i<=n;i++)
{
if(dis[i]>dis[u])
{
u=i;
}
}
memset(dis,-1,sizeof(dis));
dis[u]=0;
dfs1(u);
v=u;
for(int i=1;i<=n;i++)
{
if(dis[i]>dis[v]) v=i;
}
on[v]=1;
dfs2(u);
//以上步骤之后,所有点到u点的距离已知,接下来就用到u点的距离求答案
dfs3(u,u);//处理不在直径上的点
for(;u!=v;v=fa[v])
{
ans+=dis[v];
s.push_back({u,v});
}
printf("%lld\n",ans);
for(auto x:s)
{
printf("%lld %lld %lld\n",x[0],x[1],x[1]);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】