[BZOJ2599]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
0 1 1
1 2 2
1 3 4
Sample Output
2
HINT
2018.1.3新加数据一组,未重测
Source
很简单的一道点分治,注意一下维护的顺序,先更新答案再更新桶数组
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define M 200010 5 using namespace std; 6 int n,m,num,rt,ans,k,S; 7 int maxn[M],head[M],dis[M],d[M],size[M],t[M<<3]; 8 bool vis[M]; 9 struct point{int to,next,dis;}e[M<<1]; 10 void add(int from,int to,int dis) { 11 e[++num].next=head[from]; 12 e[num].to=to; 13 e[num].dis=dis; 14 head[from]=num; 15 } 16 void getroot(int x,int fa) { 17 size[x]=1;maxn[x]=0; 18 for(int i=head[x];i;i=e[i].next) { 19 int to=e[i].to; 20 if(to==fa||vis[to]) continue; 21 getroot(to,x),size[x]+=size[to]; 22 maxn[x]=max(maxn[x],size[to]); 23 } 24 maxn[x]=max(maxn[x],S-size[x]); 25 if(maxn[x]<maxn[rt]) rt=x; 26 } 27 void cal(int x,int fa) { 28 if(dis[x]>k) return; 29 ans=min(ans,d[x]+t[k-dis[x]]); 30 for(int i=head[x];i;i=e[i].next) { 31 int to=e[i].to; 32 if(vis[to]||to==fa) continue; 33 d[to]=d[x]+1,dis[to]=dis[x]+e[i].dis; 34 cal(to,x); 35 } 36 } 37 void insert(int x,int fa) { 38 if(dis[x]<=k) { 39 t[dis[x]]=min(t[dis[x]],d[x]); 40 for(int i=head[x];i;i=e[i].next) 41 if(!vis[e[i].to]&&e[i].to!=fa) 42 insert(e[i].to,x); 43 } 44 } 45 void del(int x,int fa) { 46 if(dis[x]<=k) { 47 t[dis[x]]=1e9; 48 for(int i=head[x];i;i=e[i].next) 49 if(!vis[e[i].to]&&e[i].to!=fa) 50 del(e[i].to,x); 51 } 52 } 53 void solve(int x) { 54 vis[x]=true;t[0]=0; 55 for(int i=head[x];i;i=e[i].next) { 56 int to=e[i].to; 57 if(vis[to]) continue; 58 d[to]=1,dis[to]=e[i].dis,cal(to,0); 59 insert(to,x); 60 } 61 for(int i=head[x];i;i=e[i].next) 62 if(!vis[e[i].to]) 63 del(e[i].to,x); 64 for(int i=head[x];i;i=e[i].next) { 65 int to=e[i].to; 66 if(vis[to]) continue; 67 rt=0,S=size[to],getroot(to,0); 68 solve(rt); 69 } 70 } 71 int main() { 72 scanf("%d%d",&n,&k);ans=n+1; 73 memset(t,1,sizeof(t)); 74 for(int i=1;i<n;i++) { 75 int a,b,c;scanf("%d%d%d",&a,&b,&c); 76 a++,b++; 77 add(a,b,c),add(b,a,c); 78 } 79 S=maxn[0]=n;getroot(1,0); 80 solve(rt); 81 if(ans>n) puts("-1"); 82 else printf("%d\n",ans); 83 return 0; 84 }