bzoj2599: [IOI2011]Race
http://www.lydsy.com/JudgeOnline/problem.php?id=2599
点分治
mi[i] 记录边权和为i时的最少边数
先更新答案,再更新mi数组,换根时清空mi
#include<cstdio> #include<iostream> #include<algorithm> #include<cstdlib> using namespace std; #define N 200001 #define K 1000001 int m; int front[N],nxt[N<<1],to[N<<1],tot,val[N<<1]; bool vis[N]; int f[N],siz[N]; int root,all; int ans=N; int mi[K]; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } void add(int u,int v,int w) { to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; val[tot]=w; to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; val[tot]=w; } void getroot(int x,int y) { //printf("%d\n",x); siz[x]=1; f[x]=0; for(int i=front[x];i;i=nxt[i]) if(to[i]!=y && !vis[to[i]]) { getroot(to[i],x); siz[x]+=siz[to[i]]; f[x]=max(f[x],siz[to[i]]); } f[x]=max(f[x],all-siz[x]); if(f[x]<f[root]) root=x; } void dfs(int x,int y,int dis,int sum,int ty) { if(ty==1 && dis==m) ans=min(ans,sum); if(dis>=m) return; if(ty==1) { if(mi[m-dis]) ans=min(ans,sum+mi[m-dis]); } else if(ty==2) mi[dis]=mi[dis] ? min(mi[dis],sum) : sum; else mi[dis]=0; for(int i=front[x];i;i=nxt[i]) if(to[i]!=y && !vis[to[i]]) dfs(to[i],x,dis+val[i],sum+1,ty); } void cal(int x) { for(int i=front[x];i;i=nxt[i]) if(!vis[to[i]]) { dfs(to[i],x,val[i],1,1); dfs(to[i],x,val[i],1,2); } for(int i=front[x];i;i=nxt[i]) if(!vis[to[i]]) dfs(to[i],x,val[i],1,3); } void work(int x) { // printf("%d\n",x); cal(x); vis[x]=true; for(int i=front[x];i;i=nxt[i]) if(!vis[to[i]]) { all=siz[to[i]]; root=0; getroot(to[i],0); work(root); } } int main() { int size = 128 << 20; char *p = (char*)malloc(size) + size; __asm__("movl %0, %%esp\n" :: "r"(p)); freopen("ioi2011-race.in","r",stdin); freopen("ioi2011-race.out","w",stdout); int n; read(n); read(m); int u,v,w; for(int i=1;i<n;++i) { read(u); u++; read(v); v++; read(w); add(u,v,w); } all=n; f[0]=n; getroot(1,0); work(root); printf("%d",ans==N ? -1 : ans); }