bzoj2599/luogu4149 [IOI2011]Race (点分治)
点分治。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 }