题意
给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小
N≤200000,K≤1000000
N
≤
200000
,
K
≤
1000000
代码
点分治的一类经典模型
#include<cstdio>
#include<algorithm>
#include<cctype>
using namespace std;
const int N=2e5+10,inf=2e9,K=1e6+10;
int n,k,ans=inf,sz[N],S,MX,rt,vis[N],mx[N],ct[K];
int head[N],to[N<<2],nxt[N<<2],w[N<<2],tot,dis[N],d[N];
inline int rd()
{
char ch=getchar();int x=0,f=1;
while(!isdigit(ch)){if(ch==-'-') f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
return x*f;
}
inline void lk(int u,int v,int c)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;w[tot]=c;}
inline void getrt(int x,int fa)
{
register int i,j;
sz[x]=1;mx[x]=0;
for(i=head[x];i;i=nxt[i]){
j=to[i];if(j==fa || vis[j]) continue;
getrt(j,x);
sz[x]+=sz[j];
mx[x]=max(mx[x],sz[j]);
}
mx[x]=max(mx[x],S-sz[x]);
if(mx[x]<MX){rt=x;MX=mx[x];}
}
inline void cal(int x,int fa)
{
register int i,j;
if(dis[x]<=k) ans=min(ans,ct[k-dis[x]]+d[x]);
for(i=head[x];i;i=nxt[i]){
j=to[i];
if(j==fa || vis[j]) continue;
d[j]=d[x]+1;dis[j]=dis[x]+w[i];
cal(j,x);
}
}
inline void update(int x,int fa)
{
if(dis[x]<=k) ct[dis[x]]=min(ct[dis[x]],d[x]);
for(register int j,i=head[x];i;i=nxt[i]){
j=to[i];if(vis[j] || j==fa)continue;
update(j,x);
}
}
inline void del(int x,int fa)
{
if(dis[x]<=k) ct[dis[x]]=inf;
for(register int j,i=head[x];i;i=nxt[i]){
j=to[i];if(vis[j] || j==fa)continue;
del(j,x);
}
}
inline void divide(int x)
{
register int i,j;
vis[x]=1;ct[0]=0;
for(i=head[x];i;i=nxt[i]){
j=to[i];
if(vis[j]) continue;
dis[j]=w[i];d[j]=1;
cal(j,x);update(j,x);
}
for(i=head[x];i;i=nxt[i]){
j=to[i];if(vis[j]) continue;
del(j,x);
}
for(i=head[x];i;i=nxt[i]){
j=to[i];if(vis[j]) continue;
S=sz[j];MX=inf;rt=0;
getrt(j,x);
divide(rt);
}
}
int main(){
register int i,j,ix,iy,iz;
n=rd();k=rd();
for(i=0;i<=k;++i) ct[i]=inf;
for(i=1;i<n;++i){ix=rd()+1;iy=rd()+1;iz=rd();lk(ix,iy,iz);lk(iy,ix,iz);}
MX=inf;S=n;getrt(1,0);divide(rt);
if(ans<inf) printf("%d\n",ans);else printf("-1\n");
}