【校內模擬】fibonacci(斐波那契通項公式)(DFS序)(樹狀數組)(樹上差分)

題面見校內OJ4695


題解:

首先利用斐波那契通項公式轉化爲等比數列求和。

然後樹上差分,考慮修改對詢問的貢獻,發現有一部分與詢問點的深度無關,另一部分有關,分開維護即可。


代碼:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const

namespace IO{
	static cs int Rlen=1<<22|1;
	static char buf[Rlen],*p1,*p2;
	inline char get_char(){return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;}
	inline char peek(){return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1;}
	inline char ga(){while(!isalpha(peek()))++p1;return gc();}
	template<typename T>
	inline T get(){
		char c;T num;
		while(!isdigit(c=gc()));num=c^48;
		while(isdigit(c=gc()))num=((num+(num<<2))<<1)+(c^48);
		return num;
	}
	inline int gi(){return get<int>();}
	inline ll gL(){return get<ll>();}
}
using namespace IO;

using std::cerr;
using std::cout;

cs int mod=1e9+7;
inline int add(int a,int b){a+=b-mod;return a+(a>>31&mod);}
inline int dec(int a,int b){a-=b;return a+(a>>31&mod);}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline int power(int a,int b,int res=1){
	for(;b;b>>=1,a=mul(a,a))(b&1)&&(res=mul(res,a));
	return res;
}
inline void Inc(int &a,int b){a+=b-mod;a+=a>>31&mod;}
inline void Dec(int &a,int b){a-=b;a+=a>>31&mod;}
inline void Mul(int &a,int b){a=mul(a,b);}
inline void ex_gcd(int a,int b,ll &x,ll &y){
	if(!b){x=1,y=0;return ;}ex_gcd(b,a%b,y,x);y-=a/b*x;
}
inline int inv(int a){
	if(!a)return 1;
	ll x,y;ex_gcd(a,mod,x,y);
	return (x%mod+mod)%mod;
}
cs int inv2=(mod+1)>>1,inv5=inv(5);

//考慮修改對詢問的貢獻,兩個等差數列求和,分別爲 z^k/(1-z)和 z^{d_y+1}\cdot z^k/(z^{d_x}(1-z))

struct cp{
	int x,y;//x + y\sqrt 5
	cp(){}
	cp(int _x,int _y=0):x(_x),y(_y){}
	friend cp operator+(cs cp &a,cs cp &b){return cp(add(a.x,b.x),add(a.y,b.y));}
	friend cp operator-(cs cp &a,cs cp &b){return cp(dec(a.x,b.x),dec(a.y,b.y));}
	friend cp operator*(cs cp &a,cs cp &b){return cp(add(mul(a.x,b.x),mul(5,mul(a.y,b.y))),add(mul(a.x,b.y),mul(a.y,b.x)));}
	friend cp operator*(cs cp &a,int b){return cp(mul(a.x,b),mul(a.y,b));}
	void operator+=(cs cp &b){*this=*this+b;}
	void operator-=(cs cp &b){*this=*this-b;}
	void operator*=(cs cp &b){*this=*this*b;}
	void operator*=(int b){Mul(x,b),Mul(y,b);}
};
inline cp power(cp a,ll b){
	cp res(1,0);
	for(;b;b>>=1,a=a*a)if(b&1)res=res*a;
	return res;
}
inline cp inv(cp a){
	return cp(a.x,dec(0,a.y))*inv(dec(mul(a.x,a.x),mul(5,mul(a.y,a.y))));
}

cs cp z=cp(1,1)*inv2,iz=inv(z),iz1=inv(cp(1)-z);

cs int N=1e5+7;

int n,m;

int last[N],nxt[N],to[N],ecnt;
inline void adde(int u,int v){
	nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v;
}

int fa[N],d[N],siz[N],son[N];
int top[N],in[N],out[N],clk;
cp w[N],iw[N];

void dfs1(int u,int p){
	w[u]=w[p]*z;iw[u]=iw[p]*iz;
	d[u]=d[p]+1;in[u]=++clk;siz[u]=1;
	for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
		dfs1(v,u);siz[u]+=siz[v];if(siz[v]>siz[son[u]])son[u]=v;
	}
	out[u]=clk;
}
void dfs2(int u,int tp){
	top[u]=tp;
	for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]])
	dfs2(v,v==son[u]?tp:v);
}
inline int LCA(int u,int v){
	while(top[u]!=top[v])d[top[u]]<d[top[v]]?v=fa[top[v]]:u=fa[top[u]];
	return d[u]<d[v]?u:v;
}
cp t1[N],t2[N];
inline cp query(cp *A,int p){
	cp res=cp(0);
	for(;p;p^=p&-p)res+=A[p];
	return res;
}
inline void update(cp *A,int p,cp ad){
	for(;p<=clk;p+=p&-p)A[p]+=ad;
}
inline void update(cp *A,int l,int r,cp ad){
	update(A,l,ad);update(A,r+1,cp(0)-ad);
}

inline cp query(int u){
	if(!u)return cp(0);
	cp v1=query(t1,in[u]),v2=w[u]*z*query(t2,in[u]);
	return v1-v2;
}

signed main(){
#ifdef zxyoi
	freopen("fibonacci.in","r",stdin);
#else 
#ifndef ONLINE_JUDGE
	freopen("fibonacci.in","r",stdin);freopen("fibonacci.out","w",stdout);
#endif
#endif
	n=gi(),m=gi();
	for(int re i=2;i<=n;++i)adde(fa[i]=gi(),i);
	w[0]=iw[0]=cp(1);dfs1(1,0);dfs2(1,1);
	while(m--){
		switch(ga()){
			case 'U':{
				int u=gi();ll k=gL();
				cp t=power(z,k);
				update(t1,in[u],out[u],t*iz1);
				update(t2,in[u],out[u],t*iz1*iw[u]);
				break;
			}
			case 'Q':{
				int u=gi(),v=gi(),p=LCA(u,v),pp=fa[p];
				cp k1=query(u),k2=query(v),k3=query(p),k4=query(pp),val=k1+k2-k3-k4;
				cout<<add(val.y,val.y)<<"\n";
				break;
			}
		}
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章