BZOJ2599 IOI2011Race

题目:一棵树,每条边有权.求一条路径,权值和等于K,且边的数量最小.

点分治,我们考虑经过根节点的路径,t[x]表示路径长为x时最少的边数,然后每次拿栈记下来清空。

注意先搜索再更新,这样可以避免同一子树内互相到达。

By:大奕哥

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=2e5+10,inf=1e9,M=1e6+10;;
 4 int n,k,rt,cnt,head[N],s[N],f[N],t[M],ans,maxn,sta[N],top,dis[N],d[N];
 5 bool v[N];
 6 struct node{
 7     int to,nex,w;
 8 }e[N<<1];
 9 void add(int x,int y,int w)
10 {
11     e[++cnt].w=w;e[cnt].nex=head[x];e[cnt].to=y;head[x]=cnt;
12 }
13 void getrt(int x,int fa)
14 {
15     s[x]=1;f[x]=0;
16     for(int i=head[x];i;i=e[i].nex)
17     {
18         int y=e[i].to;
19         if(y==fa||v[y])continue;
20         getrt(y,x);
21         f[x]=max(f[x],s[y]);
22         s[x]+=s[y];
23     }
24     f[x]=max(f[x],maxn-s[x]);
25     if(f[x]<f[rt])rt=x;
26 }
27 void calc(int x,int fa)
28 {
29     if(dis[x]<=k)ans=min(ans,t[k-dis[x]]+d[x]);
30     for(int i=head[x];i;i=e[i].nex)
31     {
32         int y=e[i].to;
33         if(v[y]||y==fa)continue;
34         dis[y]=dis[x]+e[i].w;
35         d[y]=d[x]+1;
36         calc(y,x);
37     }
38 }
39 void update(int x,int fa)
40 {
41     if(dis[x]<=k)t[dis[x]]=min(t[dis[x]],d[x]),sta[++top]=dis[x];
42     for(int i=head[x];i;i=e[i].nex)
43     {
44         int y=e[i].to;
45         if(v[y]||y==fa)continue;
46         update(y,x);
47     }
48 }
49 void work(int x)
50 {
51     v[x]=1;top=0;t[0]=0;
52     for(int i=head[x];i;i=e[i].nex)
53     {
54         int y=e[i].to;
55         if(v[y])continue;
56         dis[y]=e[i].w;d[y]=1;
57         calc(y,x);
58         update(y,x);
59     }
60     for(int i=1;i<=top;++i)t[sta[i]]=inf;
61     for(int i=head[x];i;i=e[i].nex)
62     {
63         int y=e[i].to;
64         if(v[y])continue;
65         maxn=s[y];rt=0;
66         getrt(y,x);
67         work(rt);
68     }
69 }
70 int main()
71 {
72     scanf("%d%d",&n,&k);
73     int x,y,w;
74     for(int i=1;i<n;++i)
75     {
76         scanf("%d%d%d",&x,&y,&w);
77         x++;y++;
78         add(x,y,w);add(y,x,w);
79     }
80     memset(t,0x3f,sizeof(t));
81     maxn=f[0]=ans=n;
82     getrt(1,0);
83     work(rt);
84     if(ans==n)puts("-1");
85     else printf("%d\n",ans);
86     return 0;
87 }

 

posted @ 2018-01-25 08:12  大奕哥&VANE  阅读(150)  评论(0编辑  收藏  举报