【BZOJ】1912: [Apio2010]patrol 巡逻(树的直径)
题目
传送门:QWQ
分析
$ k=1 $ 时显然就是树的直径
$ k=2 $ 时怎么做呢?
做法是把一开始树的直径上的边的边权改成$ -1 $,那么当我们第二次用这些边做环时就抵消了一开始的贡献。
所以答案就是边的数量*2 - 一开始树的直径 - 后来树的直径
P.S. 第二次求树的直径时只能dp
代码
#include <bits/stdc++.h> using namespace std; const int maxn=210000; int n,dis[maxn], inq[maxn] ; struct Edge{ int u,v,dis; }; vector<int> G[maxn]; vector<Edge> edges; queue<int> que; void addedge(int a,int b,int c){ edges.push_back((Edge){a,b,c}); edges.push_back((Edge){b,a,c}); int m=edges.size(); G[a].push_back(m-2); G[b].push_back(m-1); } int spfa(int s){ memset(dis,-127,sizeof(dis)); memset(inq,0,sizeof(inq)); dis[s]=0; que.push(s); inq[s]=1; while(!que.empty()){ int u=que.front(); que.pop(); for(int i=0;i<G[u].size();i++){ int v=edges[G[u][i]].v; if(!inq[v] && dis[v]<dis[u]+edges[G[u][i]].dis){ dis[v]=dis[u]+edges[G[u][i]].dis; if(!inq[v]){que.push(v); inq[v]=1; } } } } int q=1,ans,maxnum=-10000000; for(int i=1;i<=n;i++) if(i!=s && dis[i]==dis[s]) q=0; for(int i=1;i<=n;i++){ if(dis[i]>maxnum && (q||i!=s)){ maxnum=dis[i]; ans=i; } } return ans; } void dfs(int p,int fa){ if(dis[p]==0) return; for(int i=0;i<G[p].size();i++){ int v=edges[G[p][i]].v; if(v!=fa && dis[v]==dis[p]-1){ edges[G[p][i]].dis=-1; edges[G[p][i]^1].dis=-1; dfs(v,p); } } } int ansa=0; int dp(int x,int fa){ int big1=0,big2=0; for(int i=0;i<G[x].size();i++){ int v=edges[G[x][i]].v; if(v==fa) continue; int k=dp(v,x)+edges[G[x][i]].dis; if(big1<k){big2=big1; big1=k;} else if(big2<k){ big2=k; } } if(big1+big2 > ansa) ansa=big1+big2; return big1; } int main(){ int a,b,k; scanf("%d%d",&n,&k); for(int i=1;i<n;i++){ scanf("%d%d",&a,&b); addedge(a,b,1); } int p=spfa(1); int q=spfa(p); int ans =2*n-1-dis[q]; if(k==2){ dfs(q,0); dp(1,0); ans-=ansa-1; } printf("%d\n",ans); return 0; }