版权声明:原来这里可以拿来卖萌ヽ(・∀・)ノ https://blog.csdn.net/u012345506/article/details/86482811
由斐波那契数列的通项公式:
可以想到分别维护
和
的结果来求出答案。那么问题变成了求:
考虑为路径维护一些信息使得我们可以将两条路径的信息合并。
对于一条路径
,其中
,设:
表示该路径查询的结果值;
表示
,其中
表示从
不经过
的边能够达到的节点数目(包括他自己);
表示
。
现在将
进行合并,其中
:
(
表示以节点
为根的子树的节点数)
通过预处理
的幂我们可以在
下合并两条路径。
注意到维护的信息是满足区间减法的。于是我们预处理出根到任意节点的信息,就可以在
下求出任何路径的信息。唯一特殊的只有查询的路径从属于2条从节点到根的路径上,此时需要对最终的合并进行特判,与上述合并原理相同不再赘述。
总时间复杂度
,用离线
可以将复杂度优化为
。
以下是
的代码。
#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;
};