bzoj2599 [IOI2011]Race
题目描述:
给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 1000000。
题解:
用桶存一下,然后每次换边的时候更新答案+合并桶。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 200050 #define K 1000050 const int inf = 0x3f3f3f3f; inline int rd() { int f=1,c=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=10*c+ch-'0';ch=getchar();} return f*c; } int n,k,hed[N],cnt; struct EG { int to,nxt,v; }e[2*N]; void ae(int f,int t,int v) { e[++cnt].to = t; e[cnt].nxt = hed[f]; e[cnt].v = v; hed[f] = cnt; } int rt,sum,v[N],siz[N]; int mrk[N]; void get_rt(int u,int fa) { v[u]=0,siz[u]=1; for(int j=hed[u];j;j=e[j].nxt) { int to = e[j].to; if(mrk[to]||to==fa)continue; get_rt(to,u); siz[u]+=siz[to]; if(siz[to]>v[u])v[u]=siz[to]; } v[u] = max(v[u],sum-siz[u]); if(v[u]<v[rt])rt=u; } struct Pair{int x,d;}p[N]; int tot; int g[K],ans=inf,max_dis; void dfs(int u,int fa,int dep,int dis) { if(dis>k)return ; if(dis==k) { ans = min(ans,dep); return ; } p[++tot].x = dep,p[tot].d = dis; max_dis=max(max_dis,dis); for(int j=hed[u];j;j=e[j].nxt) { int to = e[j].to; if(to==fa||mrk[to])continue; dfs(to,u,dep+1,dis+e[j].v); } } void work(int u) { mrk[u] = 1;int mx = 0; for(int j=hed[u];j;j=e[j].nxt) { int to = e[j].to; if(mrk[to])continue; max_dis=0;tot=0; dfs(to,u,1,e[j].v); mx = max(mx,max_dis); for(int i=1;i<=tot;i++) if(g[k-p[i].d]!=inf) ans = min(ans,g[k-p[i].d]+p[i].x); for(int i=1;i<=tot;i++) if(g[p[i].d]>p[i].x)g[p[i].d]=p[i].x; } for(int i=1;i<=mx;i++)g[i]=inf; for(int j=hed[u];j;j=e[j].nxt) { int to = e[j].to; if(mrk[to])continue; rt=0,sum=siz[to]; get_rt(to,0); work(rt); } } int main() { n = rd(),k = rd(); for(int ff,tt,vv,i=1;i<n;i++) { ff = rd()+1,tt = rd()+1,vv = rd(); ae(ff,tt,vv),ae(tt,ff,vv); } memset(g,0x3f,sizeof(g)); v[0]=inf; rt=0,sum=n; get_rt(1,0); work(rt); printf("%d\n",ans==inf?-1:ans); return 0; }