洛谷 P5138 fibonacci

应该是最为详细的一篇题解了。

洛谷 P5138

  • 定义 \(d_u\) 为点 \(u\) 的深度,\(f_i\) 为斐波那契数列第 \(i\) 项,满足 \(f_0=0,f_1=1,f_i=f_{i-2}+f_{i-1}(i>2)\)(同时定义 \(i<0\)\(f_{i}=f_{i+2}-f_{i+1}\))。

  • 给出以 \(1\) 为根的 \(N\) 个点的树,每个点初始权值为 \(0\)\(M\) 次操作,两种类型:

    • \(\texttt{U }x\texttt{ }k\),将以 \(x\) 为根子树内的所有点 \(u\),将其权值加上 \(f_{d_u-d_x+k}\)

    • \(\texttt{Q }x\texttt{ }y\),查询 \(x,y\) 路径上点的权值和,模 \(10^9+7\)

  • \(N,M\le 10^5\)\(k\le 10^{18}\)

需要用到的前置知识:

Ⅰ - \(i<0\) 时,\(f_{i}=(-1)^{i-1}\times f_{-i}\)

粗略地证明:

考虑归纳。

  • 易证当 \(i=-1\)\(i=-2\) 时成立。

  • 假设在 \(k\le i\le-2\) 时成立,则当 \(i=k-1\) 时:

    • \(k\) 为奇数,则 \(k+1\)\(k-1\) 均为偶数,\(k-2\) 为奇数。有:

      \[f_{k-1}=f_{k+1}-f_{k}=-f_{-k-1}-f_{-k}=-(f_{-k-1}+f_{-k})=-f_{-k+1}=(-1)^{k-2}\times f_{-(k-1)} \]

      成立。

    • \(k\) 为偶数,则 \(k+1\)\(k-1\) 均为奇数,\(k-2\) 为偶数。有:

      \[f_{k-1}=f_{k+1}-f_{k}=f_{-k-1}-(-f_{-k})=f_{-k-1}+f_{-k}=f_{-k+1}=(-1)^{k-2}\times f_{-(k-1)} \]

      成立。

证毕。

Ⅱ - \(f_{m+n}=f_{m-1}\times f_n+f_m\times f_{n+1}\)

粗略地证明:

首先 \(f_{m-1}\times f_n+f_m\times f_{n+1}=f_{n-1}\times f_m+f_n\times f_{m+1}\)

考虑做差:

\[\begin{aligned}f_{m-1}\times f_n+f_m\times f_{n+1}-(f_{n-1}\times f_m+f_n\times f_{m+1})&=f_m\times(f_{n+1}-f_{n-1})-f_n\times(f_{m+1}-f_{m-1})\\&=f_m\times f_n-f_n\times f_m\\&=0\end{aligned} \]

所以上面那个式子是成立的。

先钦定 \(m,n\) 为自然数。同样考虑归纳。

  • 易证 \(m=0\)\(n=0\)\(m,n\in[0,1]\) 时均成立。

  • 假设在 \(m,n\in[1,k]\) 时成立,则当 \(m,n\in[1,k+1]\) 时,在原值域上新增了三种情况:

    • \(m=k+1,n\in[1,k]\) 时:

      \[\begin{aligned}f_{m+n}&=f_{m+n-2}+f_{m+n-1}\\&=f_{m-1+n-1}+f_{m-1+n}\\&=f_{m-2}\times f_{n-1}+f_{m-1}\times f_n+f_{m-2}\times f_n+f_{m-1}\times f_{n+1}\\&=f_{m-2}\times (f_{n+1}-f_{n})+f_{m-1}\times f_n+f_{m-2}\times f_n+f_{m-1}\times f_{n+1}\\&=f_{m-2}\times f_{n+1}-f_{m-2}\times f_n+f_{m-1}\times f_n+f_{m-2}\times f_n+f_{m-1}\times f_{n+1}\\&=f_{m-1}\times f_n+(f_{m-2}+f_{m-1})\times f_{n+1}\\&=f_{m-1}\times f_n+f_m\times f_{n+1}\end{aligned} \]

      成立。

    • \(m\in[1,k],n=k+1\) 时(其实本质相同,但是为了完整还是写了):

      \[\begin{aligned}f_{m+n}&=f_{m+n-2}+f_{m+n-1}\\&=f_{m-1+n-1}+f_{m+n-1}\\&=f_{m-2}\times f_{n-1}+f_{m-1}\times f_n+f_{m-1}\times f_{n-1}+f_{m}\times f_{n}\\&=f_{m-2}\times f_{n-1}+f_{m-1}\times f_{n-1}+f_{m-1}\times f_n+f_{m}\times f_{n}\\&=f_m\times f_{n-1}+f_{m+1}\times f_n\\&=f_{m-1}\times f_n+f_m\times f_{n+1}\end{aligned} \]

      成立。

    • \(m=n=k+1\) 时:

      \[\begin{aligned}f_{m+n}&=f_{m+n-2}+f_{m+n-1}\\&=f_{m+n-2}+f_{m+n-3}+f_{m+n-2}\\&=f_{m-1+n-1}+f_{m-1+n-2}+f_{m-1+n-1}\\&=f_{m-2}\times f_{n-1}+f_{m-1}\times f_n+f_{m-2}\times f_{n-2}+f_{m-1} \times f_{n-1}+ f_{m-2}\times f_{n-1}+f_{m-1}\times f_n\\&=f_{m-1}\times f_n+f_{m-2}\times(f_{n-1}+f_{n-2}+f_{n-1})+f_{m-1}\times(f_n+f_{n-1})\\&=f_{m-1}\times f_n+f_{m-2}\times f_{n+1}+f_{m-1}\times f_{n+1}\\&=f_{m-1}\times f_n+f_m\times f_{n+1}\end{aligned} \]

      成立。

因此当 \(m,n\in[0,\infty)\) 时成立。

接下来考虑负数的情况:

假设 \(m,n\in[k,\infty)\) 时成立,则当 \(m,n\in[k-1,\infty)\) 时,同样新增三种情况:

  • \(m=k-1,n\in[k,\infty)\) 时:

    \[\begin{aligned}f_{m+n}&=f_{m+n+2}-f_{m+n+1}\\&=f_{m+1+n+1}-f_{m+1+n}\\&=f_m\times f_{n+1}+f_{m+1}\times f_{n+2}-f_{m}\times f_{n}-f_{m+1}\times f_{n+1}\\&=f_m\times(f_{n+1}-f_n)+f_{m+1}\times(f_{n+2}-f_{n+1})\\&=f_{m}\times f_{n-1}+f_{m+1}\times f_n\\&=f_{m-1}\times f_n+f_m\times f_{n+1}\end{aligned} \]

    成立。

  • \(m\in[k,\infty),n=k-1\) 时:

    \[\begin{aligned}f_{m+n}&=f_{m+n+2}-f_{m+n+1}\\&=f_{m+1+n+1}-f_{m+n+1}\\&=f_{m}\times f_{n+1}+f_{m+1}\times f_{n+2}-f_{m-1}\times f_{n+1}-f_m\times f_{n+2}\\&=f_{n+1}\times(f_m-f_{m-1})+f_{n+2}\times (f_{m+1}-f_m)\\&=f_{m-2}\times f_{n+1}+f_{m-1}\times f_{n+2}\\&=f_{m-2}\times f_{n+1}+f_{m-1}\times (f_n+f_{n+1})\\&=f_{m-2}\times f_{n+1}+f_{m-1}\times f_n + f_{m-1}\times f_{n+1}\\&=f_{m-1}\times f_n+(f_{m-2}+f_{m-1})\times f_{n+1}\\&=f_{m-1}\times f_n+f_m\times f_{n+1}\end{aligned} \]

    成立。

  • \(m=n=k-1\) 时:

    \[\begin{aligned}f_{m+n}&=f_{m+n+2}-f_{m+n+1}\\&=f_{m+n+2}-(f_{m+n+3}-f_{m+n+2})\\&=f_{m+n+2}-f_{m+n+3}+f_{m+n+2}\\&=f_{m+1+n+1}-f_{m+2+n+1}+f_{m+1+n+1}\\&=f_{m}\times f_{n+1}+f_{m+1}\times f_{n+2} - f_{m+1}\times f_{n+1}-f_{m+2}\times f_{n+2} +f_{m}\times f_{n+1}+f_{m+1}\times f_{n+2}\\&=f_m\times f_{n+1}+f_{m}\times f_{n+1}+f_{m+1}\times (f_{n+2}-f_{n+1})-(f_{m+2}-f_{m+1})\times f_{n+2}\\&=f_{m}\times f_{n+1}+f_{m}\times f_{n+1}+f_{m+1}\times f_n-f_m\times f_{n+2}\\&=f_{m}\times f_{n+1}-f_m\times(f_{n+2}-f_{n+1}) +f_{m+1}\times f_n\\&=f_m\times f_{n+1}-f_m\times f_n+f_{m+1}\times f_n\\&=(f_{m+1}-f_m)\times f_n+f_m\times f_{n+1}\\&=f_{m-1}\times f_n+f_m\times f_{n+1}\end{aligned} \]

    成立。

因此当 \(m,n\in(-\infty,\infty)\) 时成立,证毕。

有了这两个结论以后,就可以开始做这道题了。

求斐波那契数列想到矩阵快速幂。路径查询问题先想树剖。将以 \(x\) 为根子树内的点 \(u\) 权值加上 \(f_{d_u-d_x+k}\),相当于加上 \(f_{d_{u}-1}\times f_{k-d_x}+f_{d_u}\times f_{k-d_x+1}\)。将 \(f_{d_{u}-1}\)\(f_{d_u}\) 分开维护(分别记为 \(a,b\)),发现系数是常数,可做。对树剖后的序列建线段树,修改操作就是将子树在序列上对应的区间的两个系数区间加,维护区间权值和 \(sum\)\(a\) 值的和 \(v_a\)\(b\) 值的和 \(v_b\)\(a\) 值的系数懒标记 \(tg_a\)\(b\) 值的系数懒标记 \(tg_b\)

\(ls\) 为左子,\(rs\) 为右子,\(x\) 为当前节点(和输入的不同)。下传就是:

void down(int x){
	if(tga[x]){//需要下传。
		sum[ls]=(sum[ls]+va[ls]*tga[x]%M)%M;//答案加上 va[ls]*tga[x],注意这里要拿 a 值的和来乘,因为 tga[x] 是当前区间的系数,区间内每一项都要乘上这么多,根据乘法分配律就是给和乘上这么多。下面同理。
		tga[ls]=(tga[ls]+tga[x])%M;
		sum[rs]=(sum[rs]+va[rs]*tga[x]%M)%M;
		tga[rs]=(tga[rs]+tga[x])%M;
		tga[x]=0;
	}
	if(tgb[x]){
		sum[ls]=(sum[ls]+vb[ls]*tgb[x]%M)%M;
		tgb[ls]=(tgb[ls]+tgb[x])%M;
		sum[rs]=(sum[rs]+vb[rs]*tgb[x]%M)%M;
		tgb[rs]=(tgb[rs]+tgb[x])%M;
		tgb[x]=0;
	}
}

查询就是跳链查询。

时间复杂度为 \(\mathcal{O}(M\log^2N)\),空间复杂度为 \(\mathcal{O}(N)\)

评测记录

$\bf\color{orange}点击查看代码$
#include<bits/stdc++.h>
#define ls x<<1
#define rs x<<1|1
using namespace std;
typedef long long ll;
const ll M=1e9+7;
const int N=1e5+5;
char op;
int n,m,f[N],t[N],h[N],d[N],sz[N],dfn[N],id,st[N],ed[N];
ll tga[N<<2],tgb[N<<2],sum[N<<2],va[N<<2],vb[N<<2];
vector<int>g[N];
struct matrix{
	int r,c;
	ll a[3][3];
	matrix(){
		memset(a,r=c=0,sizeof a);
	}
}A,B,C;
matrix operator*(matrix u,matrix v){
	matrix ret;
	ret.r=u.r;
	ret.c=v.c;
	for(int i=1;i<=u.r;++i){
		for(int j=1;j<=v.c;++j){
			for(int k=1;k<=u.c;++k){
				ret.a[i][j]=(ret.a[i][j]+u.a[i][k]*v.a[k][j]%M)%M;
			}
		}
	}
	return ret;
}
matrix qpow(matrix x,ll y){
	matrix ret=C;
	while(y){
		if(y&1ll){
			ret=ret*x;
		}
		x=x*x;
		y>>=1ll;
	}
	return ret;
}
ll fib(ll/*WA 30pts 警钟长鸣不开 long long 见祖宗*/ x){
	if(x>=0){
		return(A*qpow(B,x)).a[1][1];
	}else{
		ll ret=(A*qpow(B,-x)).a[1][1];
		return(-x)&1ll?ret:M-ret;
	}
}
void down(int x){
	if(tga[x]){
		sum[ls]=(sum[ls]+va[ls]*tga[x]%M)%M;
		tga[ls]=(tga[ls]+tga[x])%M;
		sum[rs]=(sum[rs]+va[rs]*tga[x]%M)%M;
		tga[rs]=(tga[rs]+tga[x])%M;
		tga[x]=0;
	}
	if(tgb[x]){
		sum[ls]=(sum[ls]+vb[ls]*tgb[x]%M)%M;
		tgb[ls]=(tgb[ls]+tgb[x])%M;
		sum[rs]=(sum[rs]+vb[rs]*tgb[x]%M)%M;
		tgb[rs]=(tgb[rs]+tgb[x])%M;
		tgb[x]=0;
	}
}
void insert(int x,int l,int r,int k,ll a,ll b){//插入 a,b 两个值。
	if(l^r){
		int mid=(l+r)>>1;
		if(k<=mid){
			insert(ls,l,mid,k,a,b);
		}else{
			insert(rs,mid+1,r,k,a,b);
		}
		va[x]=(va[ls]+va[rs])%M;
		vb[x]=(vb[ls]+vb[rs])%M;
	}else{
		va[x]=a;
		vb[x]=b;
	}
}
void modify(int x,int l,int r,int ql,int qr,ll a,ll b){
	if(ql<=l&&r<=qr){
		if(a){
			sum[x]=(sum[x]+va[x]*a%M)%M;
			tga[x]=(tga[x]+a)%M;
		}
		if(b){
			sum[x]=(sum[x]+vb[x]*b%M)%M;
			tgb[x]=(tgb[x]+b)%M;
		}
	}else{
		down(x);
		int mid=(l+r)>>1;
		if(ql<=mid){
			modify(ls,l,mid,ql,qr,a,b);
		}
		if(qr>mid){
			modify(rs,mid+1,r,ql,qr,a,b);
		}
		sum[x]=(sum[ls]+sum[rs])%M;
	}
}
ll query(int x,int l,int r,int ql,int qr){
	if(ql<=l&&r<=qr){
		return sum[x];
	}
	down(x);
	int mid=(l+r)>>1;
	ll ret=0;
	if(ql<=mid){
		ret=(ret+query(ls,l,mid,ql,qr))%M;
	}
	if(qr>mid){
		ret=(ret+query(rs,mid+1,r,ql,qr))%M;
	}
	return ret;
}
ll pathquery(int x,int y){
	ll ret=0;
	while(t[x]^t[y]){
		if(d[t[x]]<d[t[y]]){
			swap(x,y);
		}
		ret=(ret+query(1,1,n,dfn[t[x]],dfn[x]))%M;
		x=f[t[x]];
	}
	if(d[x]>d[y]){
		swap(x,y);
	}
	return (ret+query(1,1,n,dfn[x],dfn[y]))%M;
}
void dfs1(int u,int fa){
	sz[u]=1;
	for(int v:g[u]){
		if(v^fa){
			d[v]=d[u]+1;
			dfs1(v,f[v]=u);
			sz[u]+=sz[v];
		}
	}
}
void dfs2(int u,int fa){
	for(int v:g[u]){
		if(v^fa){
			if((sz[v]<<1)>sz[u]){
				t[h[u]=v]=t[u];
			}else{
				t[v]=v;
			}
			dfs2(v,u);
		}
	}
}
void dfs3(int u,int fa){
	insert(1,1,n,st[u]=dfn[u]=++id,fib(1ll*d[u]-1ll),fib(1ll*d[u]));
	if(h[u]){
		dfs3(h[u],u);
	}
	for(int v:g[u]){
		if((v^fa)&&(v^h[u])){
			dfs3(v,u);
		}
	}
	ed[u]=id;
}
int main(){
	A.a[A.r=1][A.c=2]=B.a[1][2]=B.a[2][1]=B.a[B.r=2][B.c=2]=C.a[1][1]=C.a[C.r=2][C.c=2]=1ll;
	scanf("%d%d",&n,&m);
	for(int i=1,u,v;i^n;++i){
		scanf("%d%d",&u,&v);
		g[u].emplace_back(v);
		g[v].emplace_back(u);
	}
	dfs1(1,0);
	dfs2(t[1]=1,0);
	dfs3(1,0);
	for(int i=1,x;i<=m;++i){
		ll y;
		scanf(" %c%d%lld",&op,&x,&y);
		if(op^'Q'){
			modify(1,1,n,st[x],ed[x],fib(y-1ll*d[x]),fib(y-1ll*d[x]+1ll));
		}else{
			printf("%lld\n",pathquery(x,(int)y));
		}
	}
}
posted @ 2023-06-01 23:50  lzyqwq  阅读(46)  评论(0)    收藏  举报