[bzoj2599] [IOI2011]Race
Description
给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 1000000
Input
第一行 两个整数 n, k
第二..n行 每行三个整数 表示一条无向边的两端和权值 (注意点的编号从0开始)
Output
一个整数 表示最小边数量 如果不存在这样的路径 输出-1
Sample Input
4 3
0 1 1
1 2 2
1 3 4
Sample Output
2
Solution
点分治,基本上是个板子。。
开个桶\(g[i]\)记录路径长度为\(i\)边数最少是多少。
注意无论怎么样\(g[0]\)都会等于\(0\),不要被边权为\(0\)的边影响了。
#include<bits/stdc++.h>
using namespace std;
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
void print(int x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}
const int maxn = 1e6+10;
const int maxm = 1e6+10;
const int inf = 1e9;
int vis[maxn],f[maxn],sz[maxn],g[maxm],head[maxn],tot,n,k,rt,size,ans=1e9;
struct edge{int to,nxt,w;}e[maxn<<1];
void add(int u,int v,int w) {e[++tot]=(edge){v,head[u],w},head[u]=tot;}
void ins(int u,int v,int w) {add(u,v,w),add(v,u,w);}
void get_rt(int x,int fa) {
sz[x]=1,f[x]=0;
for(int i=head[x];i;i=e[i].nxt)
if((!vis[e[i].to])&&e[i].to!=fa)
get_rt(e[i].to,x),sz[x]+=sz[e[i].to],f[x]=max(f[x],sz[e[i].to]);
f[x]=max(f[x],size-sz[x]);
if(f[x]<f[rt]) rt=x;
}
void get_sz(int x,int fa) {
sz[x]=1;
for(int i=head[x];i;i=e[i].nxt)
if((!vis[e[i].to])&&e[i].to!=fa) get_sz(e[i].to,x),sz[x]+=sz[e[i].to];
}
void get_ans(int x,int fa,int dep,int dis) {
if(dis>k) return ;
ans=min(ans,dep+g[k-dis]);
for(int i=head[x];i;i=e[i].nxt)
if((!vis[e[i].to])&&e[i].to!=fa) get_ans(e[i].to,x,dep+1,dis+e[i].w);
}
void get_dp(int x,int fa,int dep,int dis) {
if(dis>k) return ;
g[dis]=min(g[dis],dep);
for(int i=head[x];i;i=e[i].nxt)
if((!vis[e[i].to])&&e[i].to!=fa) get_dp(e[i].to,x,dep+1,dis+e[i].w);
}
void clear(int x,int fa,int dis) {
if(dis>k) return ;
g[dis]=inf;
for(int i=head[x];i;i=e[i].nxt)
if((!vis[e[i].to])&&e[i].to!=fa) clear(e[i].to,x,dis+e[i].w);
}
void solve(int x) {
vis[x]=1;
for(int i=head[x];i;i=e[i].nxt)
if(!vis[e[i].to]) g[0]=0,get_ans(e[i].to,x,1,e[i].w),get_dp(e[i].to,x,1,e[i].w);
for(int i=head[x];i;i=e[i].nxt)
if(!vis[e[i].to]) clear(e[i].to,x,e[i].w);
for(int i=head[x];i;i=e[i].nxt)
if(!vis[e[i].to])
get_sz(e[i].to,0),size=sz[e[i].to],rt=0,get_rt(e[i].to,0),solve(rt);
}
int main() {
read(n),read(k);memset(g,63,sizeof g);g[0]=0;
for(int x,y,z,i=1;i<n;i++) read(x),read(y),read(z),ins(x+1,y+1,z);
size=n,f[0]=maxn+1,rt=0,get_rt(1,0),solve(rt);write(ans==inf?-1:ans);
return 0;
}