1. 程式人生 > >IOI2011 Race 點分治

IOI2011 Race 點分治

div -- ioi 代碼 img col color 好題 ros

題意:

  給一棵樹,每條邊有權。求一條簡單路徑,權值和等於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 }
點分治(較短)

IOI2011 Race 點分治