51nod 1628 斐波那契树

版权声明:原来这里可以拿来卖萌ヽ(・∀・)ノ https://blog.csdn.net/u012345506/article/details/86482811

由斐波那契数列的通项公式:
f ( n ) = 1 5 ( ( 1 + 5 2 ) n ( 1 5 2 ) n ) f(n)=\frac 1 {\sqrt 5}((\frac {1+\sqrt 5} 2)^n-(\frac {1-\sqrt 5} 2)^n)
可以想到分别维护 ( 1 + 5 2 ) n (\frac {1+\sqrt 5} 2)^n ( 1 5 2 ) n (\frac {1-\sqrt 5} 2)^n 的结果来求出答案。那么问题变成了求:
i = 1 n j = i + 1 n a f ( x , y , i , j ) \sum_{i=1}^n\sum_{j=i+1}^na^{f(x,y,i,j)}

考虑为路径维护一些信息使得我们可以将两条路径的信息合并。
对于一条路径 ( u , v ) (u,v) ,其中 l c a ( u , v ) = v lca(u,v)=v ,设:
q q 表示该路径查询的结果值;
u p up 表示 x ( u , v ) A x a d e p ( u ) d e p ( x ) + 1 \sum_{x\in(u,v)}A_xa^{dep(u)-dep(x)+1} ,其中 A x A_x 表示从 x x 不经过 ( u , v ) (u,v) 的边能够达到的节点数目(包括他自己);
d o w n down 表示 x ( u , v ) A x a d e p ( x ) d e p ( v ) + 1 \sum_{x\in(u,v)}A_xa^{dep(x)-dep(v)+1}

现在将 ( u 1 , v 1 ) , ( u 2 , v 2 ) (u_1,v_1),(u_2,v_2) 进行合并,其中 f a t h e r ( v 1 ) = u 2 father(v_1)=u_2
u p 1 = u p 1 ( n s m ( v 1 ) ) a d e p ( u 1 ) d e p ( v 1 ) + 1 up_1=up_1-(n-sm(v_1))a^{dep(u_1)-dep(v_1)+1} s m ( v ) sm(v) 表示以节点 v v 为根的子树的节点数)
u p 2 = u p 2 s m ( v 1 ) a up_2=up_2-sm(v_1)a
d o w n 1 = d o w n 1 ( n s m ( v 1 ) ) a down_1=down_1-(n-sm(v_1))a
d o w n 2 = d o w n 2 s m ( v 1 ) a d e p ( u 2 ) d e p ( v 2 ) + 1 down_2=down_2-sm(v_1)a^{dep(u_2)-dep(v_2)+1}
u p n e w = u p 1 + a d e p ( u 1 ) d e p ( v 1 ) + 1 u p 2 up_{new}=up_1+a^{dep(u_1)-dep(v_1)+1}up_2
d o w n n e w = d o w n 2 + a d e p ( u 2 ) d e p ( v 2 ) + 1 d o w n 1 down_{new}=down_2+a^{dep(u_2)-dep(v_2)+1}down_1
q n e w = ( q 1 ( n s m ( v 1 ) ) × d o w n 1 ) + ( q 2 s m ( v 1 ) × u p 2 ) + d o w n 1 × u p 2 q_{new}=(q_1-(n-sm(v_1))\times down_1)+(q_2-sm(v_1)\times up_2)+down_1\times up_2
通过预处理 a a 的幂我们可以在 O ( 1 ) O(1) 下合并两条路径。
注意到维护的信息是满足区间减法的。于是我们预处理出根到任意节点的信息,就可以在 O ( 1 ) O(1) 下求出任何路径的信息。唯一特殊的只有查询的路径从属于2条从节点到根的路径上,此时需要对最终的合并进行特判,与上述合并原理相同不再赘述。

总时间复杂度 O ( n l o g n + m l o g n ) O(nlogn+mlogn) ,用离线 l c a lca 可以将复杂度优化为 O ( n + m ) O(n+m)
以下是 O ( n l o g n + m l o g n ) O(nlogn+mlogn) 的代码。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<climits>
#include<cstdio>
#include<cmath>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
//--Container
//--
typedef long long ll;

const ll md=1e9+9,_d5=383008016;const int up=1e5,zep=18;

inline ll qni(ll a,ll b){
    ll r=1;for(b=abs(b);b;b>>=1,a=a*a%md)if(b&1)r=r*a%md;
    return r;
};

int n,m;
struct eg{int u,v,nx;}gp[(up<<1)+10];int cnt,hd[up+10],dep[up+10],rsm[up+10];ll xrsm[up+10],_as[up+10];
inline void psh(int u,int v){++cnt;gp[cnt].u=u,gp[cnt].v=v,gp[cnt].nx=hd[u],hd[u]=cnt;};
int fa[up+10][zep];
int dfs(int v,int f,int d){
    int i,t=0;for(xrsm[v]=0,fa[v][0]=f,rsm[v]=1,dep[v]=d,i=hd[v];i;i=gp[i].nx)if(gp[i].v!=f){
        rsm[v]+=dfs(gp[i].v,v,d+1);
        xrsm[v]+=(ll)t*rsm[gp[i].v];
        t+=rsm[gp[i].v];
    }
    xrsm[v]+=(ll)t*(n-t);xrsm[v]+=(n-t-1);xrsm[v]%=md;
    return rsm[v];
};
void genfa(){
    int i,j;for(i=1;i<zep;++i)for(j=1;j<=n;++j)fa[j][i]=fa[fa[j][i-1]][i-1];
};
int _tcs(int v,int d){
    int i;for(i=0;d;d>>=1,++i)if(d&1)v=fa[v][i];
    return v;
};
int lca(int a,int b,bool&fg){
    if(dep[a]<dep[b])b=_tcs(b,dep[b]-dep[a]);
    else
        a=_tcs(a,dep[a]-dep[b]);
    if(a==b){fg=1;return a;}
    int i;for(i=zep-1;i>=0;--i)if(fa[a][i]!=fa[b][i])
        a=fa[a][i],b=fa[b][i];
    return a;
};

ll dcs[up+10],ucs[up+10],qsm[up+10];

inline void comb(ll _a,int u1,int v1,int u2,int v2,ll dcs1,ll ucs1,ll qsm1,ll dcs2,ll ucs2,ll qsm2,ll&dcs3,ll&ucs3,ll&qsm3){
    //we promise v1 link to u2 and ucs is begin with u,dcs begin with v
    ucs2=(ucs2+md-_a*rsm[v1]%md)%md;
    ucs1=(ucs1+md-_as[dep[u1]-dep[v1]+1]*(n-rsm[v1])%md)%md;
    dcs2=(dcs2+md-_as[dep[u2]-dep[v2]+1]*rsm[v1]%md)%md;
    dcs1=(dcs1+md-_a*(n-rsm[v1])%md)%md;
    dcs3=(dcs2+dcs1*_as[dep[u2]-dep[v2]+1])%md;
    ucs3=(ucs1+ucs2*_as[dep[u1]-dep[v1]+1])%md;
    qsm3=(qsm1+md-dcs1*(n-rsm[v1])%md)%md+(qsm2+md-ucs2*rsm[v1]%md)%md+dcs1*ucs2%md;qsm3%=md;
};

inline void _comb(ll _a,int u1,int v1,int u2,int v2,ll dcs1,ll ucs1,ll qsm1,ll dcs2,ll ucs2,ll qsm2,ll&qsm3){
    ucs2=(ucs2+md-_a*(n-rsm[u2])%md)%md;
    ucs1=(ucs1+md-_as[dep[u1]-dep[v1]+1]*rsm[u2]%md)%md;
    dcs2=(dcs2+md-_as[dep[v2]-dep[u2]+1]*(n-rsm[u2])%md)%md;
    dcs1=(dcs1+md-_a*rsm[u2]%md)%md;
    qsm3=(qsm1+md-dcs1*rsm[u2]%md)%md+(qsm2+md-ucs2*(n-rsm[u2])%md)%md+dcs1*ucs2%md;qsm3%=md;
};

inline void shap(ll _a,int u1,int v1,int u2,int v2,ll dcs3,ll ucs3,ll qsm3,ll dcs2,ll ucs2,ll qsm2,ll&dcs1,ll&ucs1,ll&qsm1){
    ucs2=(ucs2+md-_a*rsm[v1]%md)%md;
    dcs2=(dcs2+md-_as[dep[u2]-dep[v2]+1]*rsm[v1]%md)%md;
    ucs1=(ucs3+md-_as[dep[u1]-dep[v1]+1]*ucs2%md)%md;
    dcs1=(dcs3+md-dcs2)%md*qni(qni(_a,md-2),dep[v2]-dep[u2]-1)%md;
    qsm1=(qsm3+(((ll)n-rsm[v1])*dcs1%md+ucs2*rsm[v1]%md+md-qsm2+md-dcs1*ucs2%md))%md;
    ucs1=(ucs1+_as[dep[u1]-dep[v1]+1]*(n-rsm[v1]))%md;
    dcs1=(dcs1+_a*(n-rsm[v1]))%md;
};

void dfx(ll _a,int v,int f){
    if(v==1)dcs[1]=ucs[1]=_a*n%md,qsm[1]=xrsm[1]*_a%md;
    else
        comb(_a,v,v,f,1,_a*n%md,_a*n%md,xrsm[v]*_a%md,dcs[f],ucs[f],qsm[f],dcs[v],ucs[v],qsm[v]);
    int i;for(i=hd[v];i;i=gp[i].nx)if(gp[i].v!=f)dfx(_a,gp[i].v,v);
};

ll _qry(ll _a,int a,int b){
    bool fg=0;int x=lca(a,b,fg);if(fg){
        if(a==1)return qsm[b];
        if(b==1)return qsm[a];
        if(dep[b]<dep[a])swap(a,b);
        ll x,y,z;shap(_a,b,a,fa[a][0],1,dcs[b],ucs[b],qsm[b],dcs[fa[a][0]],ucs[fa[a][0]],qsm[fa[a][0]],x,y,z);
        return z;
    }
    else{
        ll dcs1,dcs2,ucs1,ucs2,qsm1,qsm2,rs;
        shap(_a,a,x,fa[x][0],1,dcs[a],ucs[a],qsm[a],dcs[fa[x][0]],ucs[fa[x][0]],qsm[fa[x][0]],dcs1,ucs1,qsm1);
        if(fa[x][0]==1)dcs2=dcs[b],ucs2=ucs[b],qsm2=qsm[b];
        else
            shap(_a,b,fa[x][0],fa[fa[x][0]][0],1,dcs[b],ucs[b],qsm[b],dcs[fa[fa[x][0]][0]],ucs[fa[fa[x][0]][0]],qsm[fa[fa[x][0]][0]],dcs2,ucs2,qsm2);
        _comb(_a,b,fa[x][0],x,a,dcs2,ucs2,qsm2,ucs1,dcs1,qsm1,rs);
        return rs;
    }
};

struct qr{int a,b;ll rs;}qrr[up+10];

void cl(){
    int i,j,k,d,t;cnt=0;scanf("%d",&n);for(i=1;i<n;++i){
        scanf("%d %d",&d,&t);psh(d,t),psh(t,d);
    }
    dfs(1,0,0);genfa();
    for(scanf("%d",&m),i=0;i<m;++i){
        scanf("%d %d",&qrr[i].a,&qrr[i].b);qrr[i].rs=0;
    }
    ll _a=(1+_d5)*qni(2,md-2)%md;
    for(_as[0]=1,i=1;i<=n;++i)_as[i]=_as[i-1]*_a%md;
    for(dfx(_a,1,0),i=0;i<m;++i){
        qrr[i].rs+=_qry(_a,qrr[i].a,qrr[i].b);
    }
    _a=(1+md-_d5)%md*qni(2,md-2)%md;
    for(i=1;i<=n;++i)_as[i]=_as[i-1]*_a%md;
    for(dfx(_a,1,0),i=0;i<m;++i){
        qrr[i].rs-=_qry(_a,qrr[i].a,qrr[i].b);
    }
    for(i=0;i<m;++i){
        printf("%lld\n",(qrr[i].rs+md)%md*qni(_d5,md-2)%md);
    }
};

int main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
#endif
    cl();
    return 0;
};

猜你喜欢

转载自blog.csdn.net/u012345506/article/details/86482811
今日推荐