[BZOJ2599][IOI2011]Race 点分治

2599: [IOI2011]Race

Time Limit: 70 Sec  Memory Limit: 128 MB
Submit: 3934  Solved: 1163
[Submit][Status][Discuss]

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
 
 
考虑点分治,每次对子树进行dfs求出子树中每个点到根的距离并记在dis[i]中,步数记在b[i]中。
同时我们开一个桶tot,记录这颗子树之前的子树中所有dis中步数的最小值。
开一个v的桶记录此时tot桶中记录的数是否为以当前u为根更新的答案。
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<cstdlib>
 5 #include<algorithm>
 6 using namespace std;
 7 struct data {
 8     int to,next,val;
 9 }e[400005];
10 int head[200005],cnt;
11 bool vis[200005];
12 void add(int u,int v,int val) {e[cnt].to=v;e[cnt].next=head[u];e[cnt].val=val;head[u]=cnt++;}
13 int son[200005],f[200005],root,sum;
14 int b[200005],dis[200005],tot[1000005];
15 int n,k;
16 int ans=0;
17 int num;
18 int v[1000005];
19 int tt=0;
20 void findroot(int x,int fa) {
21     son[x]=1;f[x]=0;
22     for(int i=head[x];i>=0;i=e[i].next) {
23         int to=e[i].to;if(to==fa||vis[to]) continue;
24         findroot(to,x);
25         son[x]+=son[to];
26         f[x]=max(f[x],son[to]);
27     }
28     f[x]=max(f[x],sum-son[x]);
29     if(f[x]<f[root]) root=x;
30     return;
31 }
32 void dfs(int x,int fa,int d,int dep) {
33     dis[++num]=d;b[num]=dep;
34     for(int i=head[x];i>=0;i=e[i].next) {
35         int to=e[i].to;if(to==fa||vis[to]) continue;
36         if(d+e[i].val>k) continue;
37         dfs(to,x,d+e[i].val,dep+1);
38     }
39 }
40 void work(int x) {
41     vis[x]=1;
42     bool flag=0;
43     for(int i=head[x];i>=0;i=e[i].next) {
44         num=0;
45         int to=e[i].to;if(vis[to]) continue;
46         if(e[i].val>k) continue;
47         dfs(to,x,e[i].val,1);
48         for(int j=1;j<=num;j++) if(dis[j]==k) ans=min(ans,b[j]);
49         if(flag)
50             for(int j=1;j<=num;j++) 
51                 if(dis[j]<=k&&v[k-dis[j]]==x) ans=min(ans,b[j]+tot[k-dis[j]]);
52         for(int j=1;j<=num;j++) 
53             if(dis[j]<=k) {
54                 if(v[dis[j]]!=x) v[dis[j]]=x,tot[dis[j]]=b[j];
55                 else tot[dis[j]]=min(tot[dis[j]],b[j]);
56             }
57         flag=1;
58     }
59     for(int i=head[x];i>=0;i=e[i].next) {
60         int to=e[i].to;
61         if(vis[to]) continue;
62         root=0;f[0]=n;sum=son[to];
63         findroot(to,x);
64         work(root);
65     }
66 }
67 int main() {
68     //freopen("gg.in","r",stdin);
69     memset(head,-1,sizeof(head));
70     scanf("%d%d",&n,&k);
71     for(int i=1;i<n;i++) {
72         int u,v,t;
73         scanf("%d%d%d",&u,&v,&t);
74         add(u+1,v+1,t);add(v+1,u+1,t);
75     }
76     sum=n;ans=n;f[0]=n;
77     findroot(1,0);
78     work(root);
79     if(ans==n) printf("-1");
80     else printf("%d",ans);
81 }
View Code

 

posted @ 2017-10-30 20:19  wls001  阅读(122)  评论(0编辑  收藏  举报