【AHOI2013复仇】NOI2012 park 一种巨另类的做法

原题地址
这个算法是由本沙茶在现场使用的那个做法扩展得来的……其实AC不了,后两个点会因为常数过大而T掉……但在BZOJ上算总时间的话能AC……

首先考虑树的情形。设F[i]为从点i开始,往子树i里面走,到达叶结点的期望长度,则很容易得到递推公式:
F[i] = (ΣF[j] + W(i, j)) / K,其中j是i的子结点,K是i的子结点个数。
至于这个式子的证明……很容易搞的,就不说了囧。
这样,可以在O(N)时间内求出以树根为起点的期望长度。那么,以其它点为起点的期望长度如何得到?
我们定义一种“扭根”操作(类似平衡树中的旋转),可以把根结点的一个子结点“扭”到根上,并使根结点作为它的子结点(也就是把父子关系交换一下)。容易发现,每次“扭根”之后,只有原来的根结点和现在的根结点这两个结点的子结点发生了变化,因此,也只有这两个结点的F值可能发生变化,只需要重新求一下即可(其实不用重新求,只需要维护一个KS[]值表示某个结点的子结点个数,然后在维护的时候加上或减去相应项,并维护KS即可,这样可以确保每次维护的时间复杂度为O(1))。注意“扭根”的顺序,需要按照DFS序,而且在遍历完一个结点回退的时候也要顺便“扭”回来。这样,就可以在O(N)的时间内得出以每个点为起点的期望长度,取它们的平均值即可。

然后考虑有环的情形,注意到,环上的结点数很少。由于只有一个环,所以先化为无向环套树形式。
设A为环上的一个结点。从A开始走,有可能走到它自己的树里,也有可能沿着环走到其它树里,但是, A在环上的两条邻边不可能都走到。也就是,可以枚举是左邻边走不到还是右邻边走不到,并将这条边删除(反正走不到,要了不如不要),这样就变成了一棵树,对这棵树按照上面的算法求F值,即可求出以A为起点, 某一条邻边走不到情况下 的期望长度。这里需要特别注意的是, 在求F[A]时,最后除的那个数不是K,而是(K+1),因为虽然这条邻边删掉了,但为了防止它走到还是要考虑一下的  。设F1[A]为A的左邻边走不到时的以A为起点的期望长度,F2[A]为 A的右邻边走不到时的以A为起点的期望长度(本沙茶在代码里全用F1表示了囧),这其中有相同的部分,就是A的两条邻边都走不到时的期望长度,此时就是往A的树内走,按照树的求法求即可,注意求F[A]时除的是(K+2),F1[A]+F2[A]再把这个相同的部分减掉,就是以A为起点的期望长度了。然后,采用“扭根”操作可以求出以 A树中所有结 为起点的期望长度 。枚举环上的所有结点,按照上述办法,就可以得到结果了。总时间复杂度为O(MN),M为环上结点总数。

代码:
#include  < iostream >
#include 
< stdio.h >
#include 
< stdlib.h >
#include 
< string .h >
using   namespace  std;
#define  re(i, n) for (int i=0; i<n; i++)
#define  re1(i, n) for (int i=1; i<=n; i++)
#define  re2(i, l, r) for (int i=l; i<r; i++)
#define  re3(i, l, r) for (int i=l; i<=r; i++)
#define  rre(i, n) for (int i=n-1; i>=0; i--)
#define  rre1(i, n) for (int i=n; i>0; i--)
#define  rre2(i, r, l) for (int i=r-1; i>=l; i--)
#define  rre3(i, r, l) for (int i=r; i>=l; i--)
#define  ll long long
const   int  MAXN  =   100010 , INF  =   ~ 0U   >>   2 ;
struct  edge {
    
int  a, b, w, pre, next;
    
bool  mr;
} E0[(MAXN 
+   1 *   3 ], E[MAXN  <<   2 ];
int  n, _n, m0, m, stk[MAXN], st[MAXN], pr[MAXN], pos_z, ts_len, TS[MAXN], Q[MAXN], pr1[MAXN], pr2[MAXN], lt[MAXN  <<   1 ], KS[MAXN];
bool  loop_ex, vst[MAXN];
double  F1[MAXN], F2[MAXN], res  =   0 ;
void  init_d0()
{
    re(i, n) E0[i].pre 
=  E0[i].next  =  i;  if  (n  &   1 ) m0  =  n  +   1 else  m0  =  n;
}
void  init_d()
{
    re(i, n) E[i].pre 
=  E[i].next  =  i; m  =  n;
}
void  add_edge0( int  a,  int  b,  int  w)
{
    E0[m0].a 
=  a; E0[m0].b  =  b; E0[m0].w  =  w; E0[m0].mr  =   0 ; E0[m0].pre  =  E0[a].pre; E0[m0].next  =  a; E0[a].pre  =  m0; E0[E0[m0].pre].next  =  m0 ++ ;
    E0[m0].a 
=  b; E0[m0].b  =  a; E0[m0].w  =  w; E0[m0].mr  =   0 ; E0[m0].pre  =  E0[b].pre; E0[m0].next  =  b; E0[b].pre  =  m0; E0[E0[m0].pre].next  =  m0 ++ ;
}
void  del_edge0( int  No)
{
    E0[E0[No].pre].next 
=  E0[No].next; E0[E0[No].next].pre  =  E0[No].pre;
    E0[E0[No 
^   1 ].pre].next  =  E0[No  ^   1 ].next; E0[E0[No  ^   1 ].next].pre  =  E0[No  ^   1 ].pre;
}
void  resu_edge0( int  No)
{
    E0[E0[No].pre].next 
=  E0[E0[No].next].pre  =  No;
    E0[E0[No 
^   1 ].pre].next  =  E0[E0[No  ^   1 ].next].pre  =  No  ^   1 ;
}
void  add_edge( int  a,  int  b,  int  w,  bool  mr)
{
    E[m].a 
=  a; E[m].b  =  b; E[m].w  =  w; E[m].mr  =  mr; E[m].pre  =  E[a].pre; E[m].next  =  a; E[a].pre  =  m; E[E[m].pre].next  =  m ++ ;
}
void  del_edge( int  No)
{
    E[E[No].pre].next 
=  E[No].next; E[E[No].next].pre  =  E[No].pre;
}
void  resu_edge( int  No)
{
    E[E[No].pre].next 
=  E[E[No].next].pre  =  No;
}
void  init()
{
    
int  m00, a0, b0, w0;
    scanf(
" %d%d " & n,  & m00); loop_ex  =  m00  ==  n; init_d0();
    re(i, m00) {
        scanf(
" %d%d%d " & a0,  & b0,  & w0);
        add_edge0(
-- a0,  -- b0, w0);
    }
}
void  prepare()
{
    re(i, n) {st[i] 
=  E0[i].next; vst[i]  =   0 ;}
    
int  x, y, tp  =   0 bool  FF; stk[ 0 =   0 ; vst[ 0 =   1 ; pos_z  =  pr[ 0 =   - 1 ;
    
while  (tp  >=   0 ) {
        x 
=  stk[tp]; FF  =   0 ;
        
for  ( int  p = st[x]; p  !=  x; p = E0[p].next) {
            y 
=  E0[p].b;
            
if  ( ! vst[y]) {
                vst[y] 
=  FF  =   1 ; stk[ ++ tp]  =  y; pr[y]  =  p; st[x]  =  E0[p].next;  break ;
            } 
else   if  (p  !=  (pr[x]  ^   1 &&  pos_z  ==   - 1 ) pos_z  =  p;
        }
        
if  ( ! FF) tp -- ;
    }
    x 
=  E0[pos_z].a; y  =  E0[pos_z].b; E0[pos_z].mr  =  E0[pos_z  ^   1 ].mr  =   1 ; ts_len  =   0 ;
    
while  (x  !=  y) {TS[ts_len ++ =  x; E0[pr[x]].mr  =  E0[pr[x]  ^   1 ].mr  =   1 ; x  =  E0[pr[x]].a;} TS[ts_len ++ =  y;
}
void  mkt( int  z)
{
    init_d(); re(j, n) vst[j] 
=   0 ;
    
int  x, y; Q[ 0 =  z; vst[z]  =   1 ;
    
for  ( int  front = 0 , rear = 0 ; front <= rear; front ++ ) {
        x 
=  Q[front];
        
for  ( int  p = E0[x].next; p  !=  x; p = E0[p].next) {
            y 
=  E0[p].b;
            
if  ( ! vst[y]) {
                vst[y] 
=   1 ; Q[ ++ rear]  =  y; pr1[y]  =  m; add_edge(x, y, E0[p].w, E0[p].mr);
            }
        }
    }
}
void  mkt2( int  z)
{
    init_d(); re(j, n) vst[j] 
=   0 ;
    
int  x, y, front, rear; Q[ 0 =  z; vst[z]  =   1 ;
    
for  (front = 0 , rear = 0 ; front <= rear; front ++ ) {
        x 
=  Q[front];
        
for  ( int  p = E0[x].next; p  !=  x; p = E0[p].next)  if  ( ! E0[p].mr) {
            y 
=  E0[p].b;
            
if  ( ! vst[y]) {
                vst[y] 
=   1 ; Q[ ++ rear]  =  y; pr1[y]  =  m; add_edge(x, y, E0[p].w,  0 );
            }
        }
    }
    _n 
=  rear  +   1 ;
}
void  solve()
{
    
int  x, y, z, sum, tp, lt_len;  bool  FF;
    
if  (loop_ex) {
        prepare();
        re(i, ts_len) {
            x 
=  TS[i];
            
if  (i  ==  ts_len  -   1 ) del_edge0(pos_z);  else  del_edge0(pr[x]);
            mkt(x);
            rre(j, n) {
                y 
=  Q[j];  if  (E[y].next  ==  y) {F1[y]  =   0 continue ;}
                
if  (y  ==  x) sum  =   1 else  sum  =   0 ; F1[y]  =   0 ;
                
for  ( int  p = E[y].next; p  !=  y; p = E[p].next) {
                    z 
=  E[p].b; F1[y]  +=  F1[z]  +  E[p].w; sum ++ ;
                }
                F1[y] 
/=  sum; KS[y]  =  sum;
            }
            res 
+=  F1[x];
            re(j, n) {st[j] 
=  E[j].next; vst[j]  =   0 ;} lt_len  =   0 ; stk[tp  =   0 =  x;
            
while  (tp  >=   0 ) {
                y 
=  stk[tp]; FF  =   0 ;
                
for  ( int  p = st[y]; p  !=  y; p = E[p].next)  if  ( ! E[p].mr) {
                    z 
=  E[p].b;
                    
if  ( ! vst[z]) {
                        vst[z] 
=  FF  =   1 ; stk[ ++ tp]  =  z; lt[lt_len ++ =  z;  break ;
                    }
                }
                
if  ( ! FF) {lt[lt_len ++ =   - -   1 ; tp -- ;}
            }
            
if  (lt_len  ==   1 ) lt_len  =   0 ;
            re(j, lt_len) {
                y 
=  lt[j];
                
if  (y  >=   0 ) {
                    z 
=  E[pr1[y]].a; del_edge(pr1[y]); pr2[z]  =  m; add_edge(y, z, E[pr1[y]].w,  0 );
                    
if  (E[z].next  ==  z) {F1[z]  =   0 ; KS[z]  =   0 ;}  else  {F1[z]  *=  KS[z] -- ; F1[z]  -=  E[pr1[y]].w  +  F1[y]; F1[z]  /=  KS[z];}
                    
if  (E[y].next  ==  y) {F1[y]  =   0 ; KS[y]  =   0 ;}  else  {F1[y]  *=  KS[y] ++ ; F1[y]  +=  E[pr1[y]].w  +  F1[z]; F1[y]  /=  KS[y];}
                    res 
+=  F1[y];
                } 
else  {
                    y 
=   - -   1 ;
                    z 
=  E[pr1[y]].a; del_edge(pr2[z]); resu_edge(pr1[y]);
                    
if  (E[y].next  ==  y) {F1[y]  =   0 ; KS[y]  =   0 ;}  else  {F1[y]  *=  KS[y] -- ; F1[y]  -=  E[pr2[z]].w  +  F1[z]; F1[y]  /=  KS[y];}
                    
if  (E[z].next  ==  z) {F1[z]  =   0 ; KS[z]  =   0 ;}  else  {F1[z]  *=  KS[z] ++ ; F1[z]  +=  E[pr2[z]].w  +  F1[y]; F1[z]  /=  KS[z];}
                }
            }
            
if  (i  ==  ts_len  -   1 ) resu_edge0(pos_z);  else  resu_edge0(pr[x]);
            
if  ( ! i) del_edge0(pos_z);  else  del_edge0(pr[TS[i  -   1 ]]);
            mkt(x);
            rre(j, n) {
                y 
=  Q[j];  if  (E[y].next  ==  y) {F1[y]  =   0 continue ;}
                
if  (y  ==  x) sum  =   1 else  sum  =   0 ; F1[y]  =   0 ;
                
for  ( int  p = E[y].next; p  !=  y; p = E[p].next) {
                    z 
=  E[p].b; F1[y]  +=  F1[z]  +  E[p].w; sum ++ ;
                }
                F1[y] 
/=  sum; KS[y]  =  sum;
            }
            res 
+=  F1[x];
            re(j, n) {st[j] 
=  E[j].next; vst[j]  =   0 ;} lt_len  =   0 ; stk[tp  =   0 =  x;
            
while  (tp  >=   0 ) {
                y 
=  stk[tp]; FF  =   0 ;
                
for  ( int  p = st[y]; p  !=  y; p = E[p].next)  if  ( ! E[p].mr) {
                    z 
=  E[p].b;
                    
if  ( ! vst[z]) {
                        vst[z] 
=  FF  =   1 ; stk[ ++ tp]  =  z; lt[lt_len ++ =  z;  break ;
                    }
                }
                
if  ( ! FF) {lt[lt_len ++ =   - -   1 ; tp -- ;}
            }
            
if  (lt_len  ==   1 ) lt_len  =   0 ;
            re(j, lt_len) {
                y 
=  lt[j];
                
if  (y  >=   0 ) {
                    z 
=  E[pr1[y]].a; del_edge(pr1[y]); pr2[z]  =  m; add_edge(y, z, E[pr1[y]].w,  0 );
                    
if  (E[z].next  ==  z) {F1[z]  =   0 ; KS[z]  =   0 ;}  else  {F1[z]  *=  KS[z] -- ; F1[z]  -=  E[pr1[y]].w  +  F1[y]; F1[z]  /=  KS[z];}
                    
if  (E[y].next  ==  y) {F1[y]  =   0 ; KS[y]  =   0 ;}  else  {F1[y]  *=  KS[y] ++ ; F1[y]  +=  E[pr1[y]].w  +  F1[z]; F1[y]  /=  KS[y];}
                    res 
+=  F1[y];
                } 
else  {
                    y 
=   - -   1 ;
                    z 
=  E[pr1[y]].a; del_edge(pr2[z]); resu_edge(pr1[y]);
                    
if  (E[y].next  ==  y) {F1[y]  =   0 ; KS[y]  =   0 ;}  else  {F1[y]  *=  KS[y] -- ; F1[y]  -=  E[pr2[z]].w  +  F1[z]; F1[y]  /=  KS[y];}
                    
if  (E[z].next  ==  z) {F1[z]  =   0 ; KS[z]  =   0 ;}  else  {F1[z]  *=  KS[z] ++ ; F1[z]  +=  E[pr2[z]].w  +  F1[y]; F1[z]  /=  KS[z];}
                }
            }
            
if  ( ! i) resu_edge0(pos_z);  else  resu_edge0(pr[TS[i  -   1 ]]);
            mkt2(x);
            rre(j, _n) {
                y 
=  Q[j];  if  (E[y].next  ==  y) {F1[y]  =   0 continue ;}
                
if  (y  ==  x) sum  =   2 else  sum  =   0 ; F1[y]  =   0 ;
                
for  ( int  p = E[y].next; p  !=  y; p = E[p].next) {
                    z 
=  E[p].b; F1[y]  +=  F1[z]  +  E[p].w; sum ++ ;
                }
                F1[y] 
/=  sum; KS[y]  =  sum;
            }
            res 
-=  F1[x];
            re(j, n) {st[j] 
=  E[j].next; vst[j]  =   0 ;} lt_len  =   0 ; stk[tp  =   0 =  x;
            
while  (tp  >=   0 ) {
                y 
=  stk[tp]; FF  =   0 ;
                
for  ( int  p = st[y]; p  !=  y; p = E[p].next) {
                    z 
=  E[p].b;
                    
if  ( ! vst[z]) {
                        vst[z] 
=  FF  =   1 ; stk[ ++ tp]  =  z; lt[lt_len ++ =  z;  break ;
                    }
                }
                
if  ( ! FF) {lt[lt_len ++ =   - -   1 ; tp -- ;}
            }
            
if  (lt_len  ==   1 ) lt_len  =   0 ;
            re(j, lt_len) {
                y 
=  lt[j];
                
if  (y  >=   0 ) {
                    z 
=  E[pr1[y]].a; del_edge(pr1[y]); pr2[z]  =  m; add_edge(y, z, E[pr1[y]].w,  0 );
                    
if  (E[z].next  ==  z) {F1[z]  =   0 ; KS[z]  =   0 ;}  else  {F1[z]  *=  KS[z] -- ; F1[z]  -=  E[pr1[y]].w  +  F1[y]; F1[z]  /=  KS[z];}
                    
if  (E[y].next  ==  y) {F1[y]  =   0 ; KS[y]  =   0 ;}  else  {F1[y]  *=  KS[y] ++ ; F1[y]  +=  E[pr1[y]].w  +  F1[z]; F1[y]  /=  KS[y];}
                    res 
-=  F1[y];
                } 
else  {
                    y 
=   - -   1 ;
                    z 
=  E[pr1[y]].a; del_edge(pr2[z]); resu_edge(pr1[y]);
                    
if  (E[y].next  ==  y) {F1[y]  =   0 ; KS[y]  =   0 ;}  else  {F1[y]  *=  KS[y] -- ; F1[y]  -=  E[pr2[z]].w  +  F1[z]; F1[y]  /=  KS[y];}
                    
if  (E[z].next  ==  z) {F1[z]  =   0 ; KS[z]  =   0 ;}  else  {F1[z]  *=  KS[z] ++ ; F1[z]  +=  E[pr2[z]].w  +  F1[y]; F1[z]  /=  KS[z];}
                }
            }
        }
    } 
else  {
        mkt(
0 );
        rre(i, n) {
            y 
=  Q[i];  if  (E[y].next  ==  y) {F1[y]  =   0 continue ;}
            sum 
=   0 ; F1[y]  =   0 ;
            
for  ( int  p = E[y].next; p  !=  y; p = E[p].next) {
                z 
=  E[p].b; F1[y]  +=  F1[z]  +  E[p].w; sum ++ ;
            }
            F1[y] 
/=  sum; KS[y]  =  sum;
        }
        res 
+=  F1[ 0 ];
        re(i, n) {st[i] 
=  E[i].next; vst[i]  =   0 ;} lt_len  =   0 ; stk[tp  =   0 =   0 ;
        
while  (tp  >=   0 ) {
            y 
=  stk[tp]; FF  =   0 ;
            
for  ( int  p = st[y]; p  !=  y; p = E[p].next)  if  ( ! E[p].mr) {
                z 
=  E[p].b;
                
if  ( ! vst[z]) {
                    vst[z] 
=  FF  =   1 ; stk[ ++ tp]  =  z; lt[lt_len ++ =  z;  break ;
                }
            }
            
if  ( ! FF) {lt[lt_len ++ =   - -   1 ; tp -- ;}
        }
        re(i, lt_len) {
            y 
=  lt[i];
            
if  (y  >=   0 ) {
                z 
=  E[pr1[y]].a; del_edge(pr1[y]); pr2[z]  =  m; add_edge(y, z, E[pr1[y]].w,  0 );
                
if  (E[z].next  ==  z) {F1[z]  =   0 ; KS[z]  =   0 ;}  else  {F1[z]  *=  KS[z] -- ; F1[z]  -=  E[pr1[y]].w  +  F1[y]; F1[z]  /=  KS[z];}
                
if  (E[y].next  ==  y) {F1[y]  =   0 ; KS[y]  =   0 ;}  else  {F1[y]  *=  KS[y] ++ ; F1[y]  +=  E[pr1[y]].w  +  F1[z]; F1[y]  /=  KS[y];}
                res 
+=  F1[y];
            } 
else  {
                y 
=   - -   1 ;
                z 
=  E[pr1[y]].a; del_edge(pr2[z]); resu_edge(pr1[y]);
                
if  (E[y].next  ==  y) {F1[y]  =   0 ; KS[y]  =   0 ;}  else  {F1[y]  *=  KS[y] -- ; F1[y]  -=  E[pr2[z]].w  +  F1[z]; F1[y]  /=  KS[y];}
                
if  (E[z].next  ==  z) {F1[z]  =   0 ; KS[z]  =   0 ;}  else  {F1[z]  *=  KS[z] ++ ; F1[z]  +=  E[pr2[z]].w  +  F1[y]; F1[z]  /=  KS[z];}
            }
        }
    }
    res 
/=  n;
}
void  pri()
{
    printf(
" %.5lf\n " , res);
}
int  main()
{
    init();
    solve();
    pri();
    
return   0 ;
}


你可能感兴趣的:(【AHOI2013复仇】NOI2012 park 一种巨另类的做法)