zoukankan      html  css  js  c++  java
  • 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
    ",ans);
    85     else printf("-1
    ");
    86     return 0;
    87 }
  • 相关阅读:
    平衡二叉树之RB树
    平衡二叉树之AVL树
    实现哈希表
    LeetCode Median of Two Sorted Arrays
    LeetCode Minimum Window Substring
    LeetCode Interleaving String
    LeetCode Regular Expression Matching
    PAT 1087 All Roads Lead to Rome
    PAT 1086 Tree Traversals Again
    LeetCode Longest Palindromic Substring
  • 原文地址:https://www.cnblogs.com/Ressed/p/9648815.html
Copyright © 2011-2022 走看看