1. 程式人生 > >bzoj2599/luogu4149 [IOI2011]Race (點分治)

bzoj2599/luogu4149 [IOI2011]Race (點分治)

cal 重點 clas har min code set get ems

點分治。WA了一萬年。

重點就是統計答案的方法

做法一(洛谷AC bzojWA 自測WA):

做點x時記到x距離為k的邊數最小值為dis[k],然後對每一對有值的dis[i]和dis[K-i],給ans[A[i]+A[K-i]]++,然後因為統計到了一部分不合法答案,就做x的兒子,給ans變成--,最後查ans的第一個有值的點,就是答案。

錯誤原因:可能這個點有一個的不合法答案,但它的邊數在等距離中不是最小的,他就不會被統計,等到一會減掉錯誤答案的時候卻會被減掉,然後就錯了

做法二 (洛谷TLE 洛谷+O2AC bzojTLE 自測AC):

記下來到x所有點的距離和邊數,按照距離排序,然後一邊正著做,一邊倒著做,找到所有距離和==K的對,統計到ans[邊數和]裏,也是要做兒子來減掉不合法答案

錯誤原因:常數太大

做法三 (AC)(感謝sbw大佬的熱心指點orz):

也是記一個dis[i]表示距離為i的最短邊數,但我們在做x這個點的時候找x的每個兒子這個子樹去做,每次先統計答案(ans=min{ans,dep+dis[K-i]}),再更新dis[i]數組,這樣就相當於我們不會查到兩端點都在同一子樹的答案,就是所有找到的都是合法的

(要把dis[0]先給成零,因為這條路徑是有可能以根節點為端點的)

 1 #include<bits/stdc++.h>
 2 #define pa pair<int,int>
 3 #define ll long long
 4 using
namespace std; 5 const int maxn=200020,maxk=1000010; 6 7 inline ll rd(){ 8 ll x=0;char c=getchar();int neg=1; 9 while(c<0||c>9){if(c==-) neg=-1;c=getchar();} 10 while(c>=0&&c<=9) x=x*10+c-0,c=getchar(); 11 return x*neg; 12 } 13 14 int N,K; 15 struct Edge{ 16 int
b,ne,l; 17 }eg[maxn*2]; 18 int egh[maxn],ect; 19 int siz[maxn],pct; 20 bool flag[maxn]; 21 int root,ms,smsiz; 22 int dis[maxk],ans=0x3f3f3f3f; 23 queue<int> dq; 24 25 26 inline void adeg(int a,int b,int l){ 27 eg[++ect].b=b;eg[ect].l=l;eg[ect].ne=egh[a];egh[a]=ect; 28 } 29 30 void getroot(int x,int f){ 31 siz[x]=1;int mm=0; 32 for(int i=egh[x];i;i=eg[i].ne){ 33 int b=eg[i].b;if(flag[b]||b==f) continue; 34 getroot(b,x); 35 siz[x]+=siz[b];mm=max(siz[b],mm); 36 }mm=max(smsiz-siz[x],mm); 37 if(mm<ms) ms=mm,root=x; 38 } 39 40 void getdis(int x,int f,int d,int dep){ 41 if(d<=K){ 42 if(dis[d]>2e5) dq.push(d); 43 dis[d]=min(dis[d],dep); 44 }else return; 45 for(int i=egh[x];i;i=eg[i].ne){ 46 int b=eg[i].b;if(flag[b]||b==f) continue; 47 getdis(b,x,d+eg[i].l,dep+1); 48 } 49 } 50 void calans(int x,int f,int d,int dep){ 51 if(d<=K){ 52 if(dis[K-d]<=2e5) ans=min(ans,dep+dis[K-d]); 53 }else return; 54 for(int i=egh[x];i;i=eg[i].ne){ 55 int b=eg[i].b;if(flag[b]||b==f) continue; 56 calans(b,x,d+eg[i].l,dep+1); 57 } 58 } 59 60 inline void solve(int x){ 61 flag[x]=1; 62 for(int i=egh[x];i;i=eg[i].ne){ 63 int b=eg[i].b;if(flag[b]) continue; 64 calans(b,x,eg[i].l,1); 65 getdis(b,x,eg[i].l,1); 66 }while(!dq.empty()) dis[dq.front()]=0x3f3f3f3f,dq.pop(); 67 int ss=smsiz; 68 for(int i=egh[x];i;i=eg[i].ne){ 69 int b=eg[i].b;if(flag[b]) continue; 70 ms=0x3f3f3f3f;smsiz=siz[b]>siz[x]?ss-siz[x]:siz[b]; 71 getroot(b,x);solve(root); 72 } 73 } 74 75 int main(){ 76 int i,j,k; 77 N=rd(),K=rd(); 78 for(i=1;i<N;i++){ 79 int a=rd()+1,b=rd()+1,c=rd(); 80 adeg(a,b,c);adeg(b,a,c); 81 }memset(dis,127,sizeof(dis));dis[0]=0; 82 smsiz=N;ms=0x3f3f3f3f;getroot(1,0); 83 solve(root); 84 if(ans<=2e5) printf("%d\n",ans); 85 else printf("-1\n"); 86 return 0; 87 }

bzoj2599/luogu4149 [IOI2011]Race (點分治)