[BZOJ 2599&COGS 2648][IOI2011]Race(点分治)
Description
给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 1000000
Solution
点分~g[i]存当前的子树中边权和为i的最小边数,h[i]存之前的子树中边权和为i的最小边数
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<vector> #define INF 0x3f3f3f3f #define N 200005 #define K 1000005 typedef long long LL; using namespace std; int n,k,ans=INF,mx,tot=0,root=0,tim=0,sign[K],g[K],h[K],vis[N],siz[N],maxv[N],head[N],cnt=0; vector<int>V; int read() { int x=0,f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } struct Node { int next,to,w; }Edges[N*2]; void addedge(int u,int v,int w) { Edges[cnt].next=head[u]; head[u]=cnt; Edges[cnt].to=v; Edges[cnt++].w=w; } void getroot(int u,int f) { siz[u]=1,maxv[u]=0; for(int i=head[u];~i;i=Edges[i].next) { int v=Edges[i].to; if(vis[v]||v==f)continue; getroot(v,u); siz[u]+=siz[v],maxv[u]=max(maxv[u],siz[v]); } maxv[u]=max(maxv[u],tot-siz[u]); if(maxv[u]<maxv[root])root=u; } void getdeep(int u,int f,int d,int c) { if(d>k)return; mx=max(mx,d); if(sign[d]!=tim)g[d]=c,sign[d]=tim,V.push_back(d); else g[d]=min(g[d],c); for(int i=head[u];~i;i=Edges[i].next) { int v=Edges[i].to; if(vis[v]||v==f)continue; getdeep(v,u,d+Edges[i].w,c+1); } } void work(int u) { vis[u]=1,h[0]=0,mx=0; for(int i=head[u];~i;i=Edges[i].next) { int v=Edges[i].to; if(vis[v])continue; V.clear(); tim++,getdeep(v,u,Edges[i].w,1); for(int j=0;j<V.size();j++) {int t=V[j];ans=min(ans,g[t]+h[k-t]);} for(int j=0;j<V.size();j++) {int t=V[j];h[t]=min(h[t],g[t]);} } for(int j=0;j<=mx;j++)h[j]=INF; for(int i=head[u];~i;i=Edges[i].next) { int v=Edges[i].to; if(vis[v])continue; root=0,tot=siz[v]; getroot(v,u),work(root); } } int main() { n=read(),k=read(); memset(h,0x3f,sizeof(h)); memset(head,-1,sizeof(head)); for(int i=1;i<n;i++) { int u=read()+1,v=read()+1,w=read(); addedge(u,v,w),addedge(v,u,w); } maxv[0]=INF,tot=n; getroot(1,0),work(root); printf("%d\n",ans==INF?-1:ans); return 0; }