IOI2011 Race 点分治

题意:

  给一棵树,每条边有权。求一条简单路径,权值和等于K,且边的数量最小。

分析:

  对于这道题,和计算长度恰好为k的路径数量差不多,只不过那个所谓的桶里不装数量,装达到这个长度的最小的边数。

  (感觉把这个桶应用好,能解决点分治的不少题目)

  当然呢,为了进一步节约时间,我们不必每次都把桶memset一次,只需要把用过的位置都记录下来,用完后还原即可。

  这里有两种实现方法,一个较长一个较短,一个稍快一个稍慢。

  其实这个题还有一种做法,就是树上启发式合并(不过我并没有去写)一道好题目本来就是很多种思路的火种,建议大家用不同的方法实现这道题。

代码:

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #include<cmath>
 6 #define ll long long
 7 using namespace std;
 8 const int N=200005;int rt,sum;
 9 struct node{int y,z,nxt;}edge[N*2];
10 int n,k,head[N],cn=0,siz[N],son[N];
11 void add(int x,int y,int z){
12     edge[++cn]=(node){y,z,head[x]};head[x]=cn;
13     edge[++cn]=(node){x,z,head[y]};head[y]=cn;
14 } bool vis[N];
15 void getrt(int x,int fa){
16     siz[x]=1;son[x]=0;
17     for(int i=head[x],y;~i;i=edge[i].nxt){
18         if((y=edge[i].y)==fa||vis[y])continue;
19         getrt(y,x);siz[x]+=siz[y];
20         if(son[x]<siz[y]) son[x]=siz[y];
21     } son[x]=max(son[x],sum-siz[x]);
22     if(son[x]<son[rt]) rt=x;
23 } int tmp[N*10],ans=1e9;
24 void dfs(int x,int fa,int d,int cnt){
25     if(d>k) return ;
26     ans=min(ans,tmp[k-d]+cnt);
27     for(int i=head[x],y;~i;i=edge[i].nxt){
28         y=edge[i].y;if(y==fa||vis[y])continue;
29         dfs(y,x,d+edge[i].z,cnt+1);
30     } return ;
31 }
32 void update(int x,int fa,int d,int cnt){
33     if(d>k) return ;
34     tmp[d]=min(tmp[d],cnt);
35     for(int i=head[x],y;~i;i=edge[i].nxt){
36         y=edge[i].y;if(y==fa||vis[y])continue;
37         update(y,x,d+edge[i].z,cnt+1);
38     } return ;
39 }
40 void clear(int x,int fa,int d){
41     if(d>k) return ;tmp[d]=1e9;
42     for(int i=head[x],y;~i;i=edge[i].nxt){
43         y=edge[i].y;if(y==fa||vis[y])continue;
44         clear(y,x,d+edge[i].z);
45     }return ;
46 }
47 void solve(int x,int sz){
48     tmp[0]=0;vis[x]=1;
49     for(int i=head[x],y;~i;i=edge[i].nxt){
50         if(vis[y=edge[i].y]) continue;
51         dfs(y,x,edge[i].z,1);
52         update(y,x,edge[i].z,1);
53     } clear(x,0,0);
54     for(int i=head[x],y;~i;i=edge[i].nxt){
55         if(vis[y=edge[i].y]) continue;
56         sum=(siz[y]>siz[x]?sz-siz[x]:siz[y]);
57         rt=0;son[0]=sum;getrt(y,0);
58         solve(rt,sum);
59     } return ;
60 }
61 int main(){
62     memset(head,-1,sizeof(head));
63     scanf("%d%d",&n,&k);int t1,t2,t3;
64     for(int i=1;i<n;i++){
65         scanf("%d%d%d",&t1,&t2,&t3);
66         add(t1+1,t2+1,t3);
67     } for(int i=0;i<=k;i++) tmp[i]=1e9;
68     sum=n;rt=0;son[0]=n;
69     getrt(1,0);solve(rt,n);
70     if(ans!=1e9) printf("%d\n",ans);
71     else puts("-1");return 0;
72 }
点分治
 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 const int N=2000005,M=1000005;
 5 struct link{int l,d;}q[N];
 6 int h[N],n,m,k,mx[N],dis[N];
 7 ll t[M],ans=0;int sm,tmp[N];
 8 struct node{int y,z,nxt;}e[N*2];
 9 int d[N],rt,vis[N],siz[N],c=1,cnt=0;
10 void add(int x,int y,int z){
11     e[++c]=(node){y,z,h[x]};h[x]=c;
12     e[++c]=(node){x,z,h[y]};h[y]=c;
13 } void getrt(int x,int fa){
14     siz[x]=1;mx[x]=0;
15     for(int i=h[x],y;i;i=e[i].nxt)
16     if((y=e[i].y)!=fa&&!vis[y])
17     getrt(y,x),siz[x]+=siz[y],
18     mx[x]=max(mx[x],siz[y]);
19     mx[x]=max(mx[x],sm-siz[x]);
20     if(mx[x]<mx[rt]) rt=x;return ;
21 } void dfs(int x,int fa){
22     q[++cnt]=(link){d[x],dis[x]};
23     for(int i=h[x],y;i;i=e[i].nxt)
24     if((y=e[i].y)!=fa&&!vis[y])
25     d[y]=d[x]+e[i].z,dis[y]=dis[x]+1,
26     dfs(y,x);return ;
27 } void calc(int x){ tmp[0]=0;
28     for(int i=h[x],y;i;i=e[i].nxt)
29     if(!vis[y=e[i].y]){
30         cnt=0;d[y]=e[i].z;dis[y]=1;dfs(y,x);
31         for(int j=cnt;j;j--)
32         if(q[j].l<=k) ans=
33         min(t[k-q[j].l]+q[j].d,ans);
34         for(int j=cnt;j;j--)
35         if(q[j].l<=k) t[q[j].l]=
36         min(t[q[j].l],q[j].d*1ll),
37         tmp[++tmp[0]]=q[j].l;
38     } for(int i=tmp[0];i;i--) t[tmp[i]]=2e9;
39 } void solve(int x){
40     vis[x]=1;t[0]=0;calc(x);
41     for(int i=h[x],y;i;i=e[i].nxt)
42     if(!vis[y=e[i].y]){
43         sm=siz[y];mx[rt=0]=N;
44         getrt(y,0);solve(rt);
45     } return ;
46 } int main(){
47     scanf("%d%d",&n,&k);ans=2e9;
48     memset(t,0x3f,sizeof(t));
49     for(int i=1,x,y,z;i<n;i++)
50     scanf("%d%d%d",&x,&y,&z),
51     add(x+1,y+1,z);mx[rt]=sm=n;
52     getrt(1,0);solve(rt);
53     if(ans>=1e9) puts("-1");else
54     printf("%lld\n",ans);return 0;
55 }
点分治(较短)

猜你喜欢

转载自www.cnblogs.com/Alan-Luo/p/10424317.html