P3629 [APIO2010] 巡逻 (树的直径)
(这道题考察了求直径的两种方法......)
在原图中,每条边要经过两次,增加1条后,形成了一个环,那么环上的边只需要经过一次了(大量画图分析得),再增加一条又会形成一个环,如果这两个环有重叠,重叠部分还是要经过两次,就浪费了,所以我们先找直径(两次dfs),在直径的两个端点连一条边,就可以得到k=1的答案了,如果k=2,将环上的边权都设为-1,再在新图上用DP求新的直径(因为边权有负,要用DP),最后也就得到k=2时的答案了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=1e5+10; 4 int to[N<<1],nxt[N<<1],edge[N<<1],head[N],tot; 5 int n,k,p,q; 6 int d[N],pre[N],L2; 7 8 void add(int x,int y){ 9 nxt[++tot]=head[x]; 10 head[x]=tot; 11 to[tot]=y; 12 edge[tot]=1; 13 } 14 15 void dfs1(int u,int f){ 16 if(d[u]>d[p]) p=u; 17 for(int i=head[u];i;i=nxt[i]){ 18 int v=to[i]; 19 if(v==f) continue; 20 d[v]=d[u]+edge[i]; 22 dfs1(v,u); 23 } 24 } 25 26 void dfs2(int u,int f){ 27 if(d[u]>d[q]) q=u; 28 for(int i=head[u];i;i=nxt[i]){ 29 int v=to[i]; 30 if(v==f) continue; 31 d[v]=d[u]+edge[i]; 32 pre[v]=i;//记录路径 33 dfs2(v,u); 34 } 35 } 36 37 void update(int q,int p){ 38 while(q!=p){ 39 edge[pre[q]]=-1; 40 edge[pre[q]^1]=-1;//正反向边都变为-1 41 q=to[pre[q]^1]; 42 } 43 } 44 45 void dp(int x,int f){//树形DP求直径 46 //d[]表示向下可以走的最远距离 47 for(int i=head[x];i;i=nxt[i]){ 48 int y=to[i]; 49 if(y==f) continue; 50 dp(y,x); 51 L2=max(L2,d[y]+d[x]+edge[i]); 52 d[x]=max(d[x],d[y]+edge[i]); 53 } 54 } 55 56 int main(){ 57 cin>>n>>k; 58 tot=1; 59 for(int i=1;i<n;i++){ 60 int x,y; 61 scanf("%d%d",&x,&y); 62 add(x,y);add(y,x); 63 } 64 dfs1(1,0); 65 memset(d,0,sizeof(d)); 66 dfs2(p,0); 67 int ans=2*(n-1)-d[q]+1; 68 if(k==1){ 69 cout<<ans<<endl; 70 return 0; 71 } 72 update(q,p); 73 memset(d,0,sizeof(d)); 74 dp(1,0); 75 cout<<ans-L2+1<<endl; 76 }
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
标签:
树的直径
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现