BZOJ 3124 SDOI2013 直径
首先直径是很好求的,先以任意点为根DFS求出最远点,再以最远点为根求出第二个点
两个点之间的距离即为直径
显然对于第二问,答案是直径上的某一段,且满足不可向左右扩展出跟直径等长的路径
那么我们就可以暴力枚举直径上的点,看看它是否可以向右和向左扩展即可
#include<cstdio> #include<algorithm> #include<cstdlib> #include<cstring> #include<iostream> using namespace std; typedef long long LL; const int maxn=200010; int n,u,v,w; int A,B,L,ans; int h[maxn],cnt=1; struct edge{ int to,next,w; }G[maxn<<1]; LL dis[maxn],now,tmp,D; int fa[maxn]; bool vis[maxn]; void add(int x,int y,int z){++cnt;G[cnt].to=y;G[cnt].next=h[x];G[cnt].w=z;h[x]=cnt;} void read(int &num){ num=0;char ch=getchar(); while(ch<'!')ch=getchar(); while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar(); } void DFS(int u,int f,int &c){ if(dis[u]>now)now=dis[u],c=u; for(int i=h[u];i;i=G[i].next){ int v=G[i].to; if(v==f)continue; dis[v]=dis[u]+G[i].w; fa[v]=i; DFS(v,u,c); }return; } void Get_Len(){ now=-1;dis[1]=0;fa[1]=0;DFS(1,-1,A); now=-1;dis[A]=0;fa[A]=0;DFS(A,-1,B); printf("%lld\n",dis[B]);D=dis[B]; } void check(int u,int f){ if(dis[u]>tmp)tmp=dis[u]; for(int i=h[u];i;i=G[i].next){ int v=G[i].to; if(v==f)continue; if(vis[v])continue; dis[v]=dis[u]+G[i].w; check(v,u); }return; } void Get_ans(){ now=0; for(int i=B;i;i=G[fa[i]^1].to)vis[i]=true; for(int i=fa[B];i;i=fa[G[i^1].to]){ ans++;now+=G[i].w; tmp=-1;dis[G[i^1].to]=0; check(G[i^1].to,-1); if(tmp==now)L=ans; if(tmp==D-now)break; }printf("%d\n",ans-L); } int main(){ read(n); for(int i=1;i<n;++i){ read(u);read(v);read(w); add(u,v,w);add(v,u,w); } Get_Len();Get_ans(); return 0; }