显然需要分类讨论了,首先理解k==0即原图时按照dfs序来说 , 每条边至少走两次;
k==1,相当于可以省去dfs回溯时第二次走过某条路径的浪费,所以答案是k==0的答案-直径 ;
k==2,和k==1同理,答案是k==0时的答案-两条边不相交的链的最大和,先做一次直径,将直径上的边边权都赋值为取为相反数,再做一次直径即可;(应该边权不只有1也是适用的吧,注意第二次的边权有负值只能用dp求直径)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=100010; 4 int n,k,o=2,hd[N],mx,mx1,mx2,s1[N],s2[N],dia; 5 struct Edge{int v,nt,w;}E[N<<1]; 6 void adde(int u,int v,int w){ 7 E[o]=(Edge){v,hd[u],w};hd[u]=o++; 8 E[o]=(Edge){u,hd[v],w};hd[v]=o++; 9 }10 int dfs(int u,int fa){11 int mx1=0,mx2=0;12 for(int i=hd[u];~i;i=E[i].nt){13 int v=E[i].v;14 if(v==fa)continue;15 int w = E[i].w + dfs(v,u);16 if(w>mx1)mx2=mx1,s2[u]=s1[u],mx1=w,s1[u]=i;17 else if(w>mx2)mx2=w,s2[u]=i;18 }19 if(mx1+mx2>dia)mx=u,dia=mx1+mx2;20 return mx1;21 }22 int main(){23 freopen("bzoj1912.in","r",stdin);24 freopen("bzoj1912.out","w",stdout);25 scanf("%d%d",&n,&k);26 memset(hd,-1,sizeof(hd));27 for(int i=1,u,v;i<n;i++){28 scanf("%d%d",&u,&v);29 adde(u,v,1);30 }31 int ans=(n-1)<<1;32 dia=0;dfs(1,0);33 ans=ans-dia+1;34 if(k==2){35 for(int i=s1[mx];i;i=s1[E[i].v])E[i].w=E[i^1].w=-1;36 for(int i=s2[mx];i;i=s1[E[i].v])E[i].w=E[i^1].w=-1;37 dia=0;dfs(1,0);38 ans=ans-dia+1;39 }40 printf("%d\n",ans);41 return 0;42 }
bzoj1912