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 }

 

posted @ 2018-09-14 20:33  Ressed  阅读(248)  评论(0编辑  收藏  举报