P4149 [IOI2011]Race
淀粉质点分治
处理书上路径,非常套路
(dsu on tree写挂了改不过来....)
#include<cstdio> #include<cstring> inline int Min(int a,int b){return a<b?a:b;} inline int Max(int a,int b){return a>b?a:b;} void read(int &x){ char c=getchar();x=0; while(c<'0'||c>'9') c=getchar(); while('0'<=c&&c<='9') x=x*10+c-48,c=getchar(); } #define N 200005 int n,k,dis[N],d[N],siz[N],mx[N],rt,sum; int D[1000005],tp,S[N],cc,q[N],ans=1e9; bool vis[N]; int cnt,hd[N],nxt[N<<1],ed[N],poi[N<<1],val[N<<1]; inline void adde(int x,int y,int v){ nxt[ed[x]]=++cnt, hd[x]=hd[x]?hd[x]:cnt, ed[x]=cnt, poi[cnt]=y, val[cnt]=v; } #define to poi[i] #define Edge for(int i=hd[x];i;i=nxt[i]) void grt(int x,int fa){ siz[x]=1; mx[x]=0;//记得清零mx数组! Edge if(!vis[to]&&to!=fa){ grt(to,x); siz[x]+=siz[to]; mx[x]=Max(mx[x],siz[to]); }mx[x]=Max(mx[x],sum-siz[x]); if(mx[x]<mx[rt]) rt=x; } void gdis(int x,int fa){ S[++tp]=x; d[x]=d[fa]+1; Edge if(!vis[to]&&to!=fa) dis[to]=dis[x]+val[i],gdis(to,x); } void calc(int x){ cc=0; D[0]=d[x]=0; Edge if(!vis[to]){ tp=0; dis[to]=val[i]; gdis(to,x); for(int j=1;j<=tp;++j) if(dis[S[j]]<=k) ans=Min(ans,D[k-dis[S[j]]]+d[S[j]]); for(int j=1;j<=tp;++j) if(dis[S[j]]<=k){ D[dis[S[j]]]=Min(D[dis[S[j]]],d[S[j]]); q[++cc]=dis[S[j]]; } } for(int i=1;i<=cc;++i) D[q[i]]=1e9; } void solve(int x){ vis[x]=1; calc(x); Edge if(!vis[to]) rt=0,sum=siz[to],grt(to,x),solve(rt); } int main(){ memset(D,63,sizeof(D)); read(n);read(k); for(int i=1,U,V,W;i<n;++i) read(U),read(V),read(W),adde(U+1,V+1,W),adde(V+1,U+1,W); mx[rt=0]=1e9; sum=n; grt(1,0); solve(rt); if(ans>=n) ans=-1; printf("%d",ans); return 0; }