description
给一棵树,问你直径长度与被所有直径经过的边的数量。
solution
直径的长度以及直径的路径可以由两遍dfs求得与记录。
易发现,被所有直径经过的边集可以构成连续一段的路径。
反证:如下图:
因此按上面所说找到任意一条直径路径后,找满足答案路径(边集)的左右断点。
设直径(到的路径)上的点不经过其它直径上的点可以延伸的最长距离为
如果等于了到的距离,说明到的边都可被替换,因此从左往右找,找到第一个不满足的点即是右端点(右边的全不行)。
同理,从右端点往左找,找到最后一个不等于到距离的即是左端点。
code
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
ll dis[N],dist;
int nxt[N],to[N],head[N],len[N],ecnt;
void add_edge(int u,int v,int w) {nxt[++ecnt]=head[u];len[ecnt]=w;to[ecnt]=v;head[u]=ecnt;}
int id,pre[N],com[N];
bool mark[N];
void dfs1(int u,int fa,ll D) {
if(D>dist) {dist=D;id=u;}
for(int i=head[u];i;i=nxt[i]) {
int v=to[i];if(v==fa||mark[v])continue;
dfs1(v,u,D+len[i]);
}
}
void dfs2(int u,int fa) {
if(dis[u]>dist) {dist=dis[u];id=u;}
for(int i=head[u];i;i=nxt[i]) {
int v=to[i];if(v==fa)continue;
dis[v]=dis[u]+len[i];pre[v]=u;
dfs2(v,u);
}
}
int main() {
int n,st,ed;scanf("%d",&n);
for(int i=1;i<n;i++) {
int u,v,w;scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w),add_edge(v,u,w);
}
id=-1;dist=0;dfs1(1,0,0);st=id;
id=-1;dist=0;dfs2(st,0);ed=id;
printf("%lld\n",dist);
for(int i=ed;i;i=pre[i]) {
mark[i]=1;
// printf("%d ",i);
com[pre[i]]=i;
}
// puts("");
int i;
for(i=st;i;i=com[i]) {
id=-1;dist=0;dfs1(i,0,0);
if(dist==dis[ed]-dis[i]) break;
}
int ans=0;
for(;i;i=pre[i]) {
id=-1;dist=0;dfs1(i,0,0);
if(dist==dis[i]) break;
ans++;
}
printf("%d",ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
2021-07-13 B - A Simple Task