【51nod 1628】 非波那契樹(二次剩餘 / 倍增)

傳送門

顯然利用斐波那契通項公式來做
對於f(n)=((1+5)2)n,((15)2)nf(n)=(\frac{(1+\sqrt 5)}{2})^n,(\frac{(1-\sqrt 5)}{2})^n分別計算

那麼這時候就有f(a+b)=f(a)f(b)f(a+b)=f(a)f(b)
考慮倍增,維護(u,v,s,vl,vr)(u,v,s,vl,vr)表示一段最下面點爲uu,最上面爲vv,所有點對和u,vu,v公共點數的ff的和爲ss,所有點到v/uv / u的距離的ffvl/vrvl/vr

發現這時候是可以合併信息的
假設合併(u,v,s1,vl1,vr1),(x,y,s2,vl2,vr2)(u,v,s_1,vl_1,vr_1),(x,y,s_2,vl_2,vr_2),其中xxvv的祖先
l1=dis(u,v),l2=dis(x,y),L=vl1(nsizv)bas,R=vr2sizvbasl1=dis(u,v),l_2=dis(x,y),L=vl_1-(n-siz_v)*bas,R=vr_2-siz_v*bas
LL的意義就是vv子樹內的點到vvu,vu,v的公共點數的ff
RR類似爲vv子樹外的到xxx,yx,y
那麼vl=vl2+basl2(Lsiz[v]),vr=vr1+basl1(R(nsizv)),s=s1+s2+LRL(nsizv)Rsizvvl=vl_2+bas^{l_2}(L-siz[v]),vr=vr_1+bas^{l_1}(R-(n-siz_v)),s=s_1+s_2+L*R-L*(n-siz_v)-R*siz_v

於是維護一個倍增數組v[i][u]v[i][u]表示uu往上2i2^i個點(包括自己)的信息
lcalca特判

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define pb push_back
#define re register
#define ll long long
#define pii pair<int,int>
#define fi first
#define bg begin
#define se second
#define poly vector<int>
cs int RLEN=1<<20|1;
inline char gc(){
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob)?EOF:*ib++;
}
#define gc getchar
inline int read(){
	char ch=gc();
	int res=0;bool f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
	return f?res:-res;
}
template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int mod=1e9+9;
inline int add(int a,int b){return (a+=b)>=mod?a-mod:a;}
inline void Add(int &a,int b){(a+=b)>=mod?(a-=mod):0;}
inline int dec(int a,int b){a-=b;return a+(a>>31&mod);}
inline void Dec(int &a,int b){a-=b,a+=a>>31&mod;}
inline int mul(int a,int b){static ll r;r=1ll*a*b;return r>=mod?r%mod:r;}
inline void Mul(int &a,int b){static ll r;r=1ll*a*b;a=r>=mod?r%mod:r;}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,Mul(a,a))(b&1)&&(Mul(res,a),1);return res;}
inline int Inv(int x){return ksm(x,mod-2);}
cs int sqrt5=383008016,N=100005,M=20,iv2=Inv(2),iv=Inv(sqrt5);
// sqrt5=383008016,616991993;
int fa[M][N],*ff,dep[N],siz[N],vl[N];
int n,q,bas,pw[N],ans[N];
pii ask[N];
vector<int>e[N];
struct node{
	int u,v,s,vl,vr;
	friend inline node operator +(cs node &a,cs node &b){
		int l1=dep[a.u]-dep[a.v]+1,l2=dep[b.u]-dep[b.v]+1;
		int L=dec(a.vl,mul(n-siz[a.v],bas)),R=dec(b.vr,mul(siz[a.v],bas));
		node c;
		c.u=a.u,c.v=b.v;
		c.s=add(add(a.s,b.s),dec(mul(L,R),add(mul(L,n-siz[a.v]),mul(R,siz[a.v]))));
		c.vl=add(b.vl,mul(pw[l2],dec(L,siz[a.v])));
		c.vr=add(a.vr,mul(pw[l1],dec(R,n-siz[a.v])));
		return c;
	}
}v[M][N];
void dfs(int u){
	for(int i=1;i<M&&fa[i-1][u];i++)fa[i][u]=fa[i-1][fa[i-1][u]];
	siz[u]=1;
	for(int &v:e[u]){
		if(v==fa[0][u])continue;
		fa[0][v]=u,dep[v]=dep[u]+1;
		dfs(v);
		Add(vl[u],mul(siz[u],siz[v]));
		siz[u]+=siz[v];
	}
	Add(vl[u],mul(siz[u],n-siz[u]));
}
inline int Lca(int u,int v){
	if(dep[u]<dep[v])swap(u,v);
	for(int i=19;~i;i--)if(dep[fa[i][u]]>=dep[v])u=fa[i][u];
	if(u==v)return u;
	for(int i=19;~i;i--)if(fa[i][u]!=fa[i][v])u=fa[i][u],v=fa[i][v];
	return fa[0][u];
}
inline node calc(int u,int k){
	node res=v[0][u];k--,u=ff[u];
	for(int i=19;~i;i--)
		if(k&(1<<i))res=res+v[i][u],u=fa[i][u];
	return res;
}
inline void solve(int coef){
	for(int i=1;i<=n;i++){
		v[0][i].u=v[0][i].v=i;
		v[0][i].s=mul(vl[i],bas);
		v[0][i].vl=v[0][i].vr=mul(n,bas);
	}
	for(int i=1;i<20;i++)
	for(int u=1;u<=n;u++)
	if(dep[u]>=(1<<i))v[i][u]=v[i-1][u]+v[i-1][fa[i-1][u]];
	for(int i=1;i<=q;i++){
		int u=ask[i].fi,v=ask[i].se,lca=Lca(u,v);
		if(dep[u]<dep[v])swap(u,v);
		node a=calc(u,dep[u]-dep[lca]+1);
		if(v==lca){
			Add(ans[i],mul(coef,a.s));
		}
		else{
			node b=calc(v,dep[v]-dep[lca]);
			swap(a.vl,a.vr);
			Add(ans[i],mul(coef,(b+a).s));
		}
	}
}
int main(){
	#ifdef Stargazer
	freopen("lx.in","r",stdin);
	#endif
	n=read();
	for(int i=1;i<n;i++){
		int u=read(),v=read();
		e[u].pb(v),e[v].pb(u);
	}
	dep[1]=1,dfs(1);ff=fa[0];
	q=read();
	for(int i=1;i<=q;i++)ask[i].fi=read(),ask[i].se=read();
	bas=mul(sqrt5+1,iv2);
	pw[0]=1;
	for(int i=1;i<=n;i++)pw[i]=mul(pw[i-1],bas);
	solve(1);
	bas=mul(dec(1,sqrt5),iv2);
	for(int i=1;i<=n;i++)pw[i]=mul(pw[i-1],bas);
	solve(mod-1);
	for(int i=1,iv=Inv(sqrt5);i<=q;i++)cout<<mul(ans[i],iv)<<'\n';
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章