2599: [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
 
点分治来求就好了,平常我们做点分治的时候要去除在子树中的情况,
这道题怎么去呢?好像不好去。。。那么就不去了。。。
因为我们想一下,如果答案被子树中的两个点更新了,那么,答案一定多加了一个重复的距离,
那当我们分治下去的时候就会发现,一定可以以更优的答案来更新掉当前答案,这样就好了。
 1 #include<iostream>
 2 #include<cstdlib>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<algorithm>
 7 #include<string>
 8 #include<map>
 9 #include<queue>
10 #include<vector>
11 #include<set>
12 #define inf 1000000000
13 #define maxn 200000+5
14 #define maxm 2000000+5
15 #define eps 1e-10
16 #define ll long long
17 #define for0(i,n) for(int i=0;i<=(n);i++)
18 #define for1(i,n) for(int i=1;i<=(n);i++)
19 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
20 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
21 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go)
22 using namespace std;
23 int read(){
24     int x=0,f=1;char ch=getchar();
25     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
26     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
27     return x*f;
28 }
29 struct edge{
30     int go,next,w;
31 }e[2*maxn];
32 int n,k,cnt,tot,sum,rt,ans=inf,f[maxn],g[maxm],d[maxn][2],head[maxn],s[maxn];
33 bool v[maxn];
34 void insert(int x,int y,int z){
35     e[++tot]=(edge){y,head[x],z};head[x]=tot;
36     e[++tot]=(edge){x,head[y],z};head[y]=tot;
37 }
38 void getroot(int x,int fa){
39     s[x]=1;f[x]=0;
40     for4(i,x)
41         if(!v[y]&&y!=fa){
42             getroot(y,x);
43             s[x]+=s[y];
44             f[x]=max(f[x],s[y]);
45         }
46     f[x]=max(f[x],sum-f[x]);
47     if(f[x]<f[rt])rt=x;
48 }
49 void getdeep(int x,int fa,int w1,int w2){
50     d[++cnt][0]=w1;d[cnt][1]=w2;
51     for4(i,x)
52         if(!v[y]&&y!=fa)
53             getdeep(y,x,w1+e[i].w,w2+1);
54 }
55 void work(int x){
56     v[x]=1;
57     for4(i,x)
58         if(!v[y]){
59             cnt=0;
60             getdeep(y,x,e[i].w,1);
61             for1(j,cnt)
62                 if(d[j][0]<=k)ans=min(ans,g[k-d[j][0]]+d[j][1]);
63             for1(j,cnt)
64                 if(d[j][0]<=k)g[d[j][0]]=min(g[d[j][0]],d[j][1]);
65         }
66     ans=min(ans,g[k]);
67     for4(i,x)
68         if(!v[y]){
69             cnt=0;
70             getdeep(y,x,e[i].w,1);
71             for1(j,cnt)
72                 if(d[j][0]<=k)
73                     g[d[j][0]]=inf;
74         }
75     for4(i,x)
76         if(!v[y]){
77             sum=s[y];rt=0;
78             getroot(y,x);
79             work(rt);
80         }
81 }
82 int main(){
83     //freopen("input.txt","r",stdin);
84     //freopen("output.txt","w",stdout);
85     n=read();k=read();
86     for0(i,k)g[i]=inf;
87     for1(i,n-1){
88         int x=read()+1,y=read()+1,z=read();insert(x,y,z);
89     }
90     f[rt=0]=inf;
91     sum=n;
92     getroot(1,0);
93     work(rt);
94     if(ans>=n)ans=-1;
95     cout<<ans<<endl;
96     return 0;
97 }
View Code

ps:这让我想到一道并查集的题。。。http://www.cnblogs.com/htwx/articles/4782458.html

posted @ 2016-07-12 17:42  HTWX  阅读(113)  评论(0编辑  收藏  举报