一本通 高手训练 1765 树上斐波那契 矩阵乘法 树链剖分
LINK:树上斐波那契
这道题关于广义斐波那契以及斐波那契的性质的一个题目。
设\(f_a\)表示斐波那契数列的第a项 那么有\(f_{a+b}=f_{a-1}\cdot f_b+f_{a}\cdot f_{b+1}\)
关于证明 可以采用数学归纳法。挺容易的。
这道题是x子树内增加 \(f_{k+D}\)其中k为常数 D为x子树内的点距x的距离。
容易转换为 \(f_{k+d_u-d_x}\) 套上面的斐波那契类似于结论的等式就可以发现每次是单点增加定值可以直接维护和了。
值得一提的是 由于k很大 所以需要矩阵乘法。
还有就是 下表为负的情况 搞出广义斐波那契 使用即可。
还是比较好码的题目。
//#include<bits\stdc++.h>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<algorithm>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#define ll long long
#define db double
#define INF 1000000000000000ll
#define ldb long double
#define pb push_back
#define put_(x) printf("%d ",x);
#define get(x) x=read()
#define gt(x) scanf("%d",&x)
#define gi(x) scanf("%lf",&x)
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define gc(a) scanf("%s",a+1)
#define rep(p,n,i) for(RE int i=p;i<=n;++i)
#define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define fep(n,p,i) for(RE int i=n;i>=p;--i)
#define pii pair<int,int>
#define mk make_pair
#define RE register
#define P 1000000007
#define S second
#define F first
#define gf(x) scanf("%lf",&x)
#define pf(x) ((x)*(x))
#define ull unsigned long long
#define ui unsigned
#define EPS 1e-8
#define mod 1000000007
#define sq sqrt
#define zz p<<1
#define yy p<<1|1
#define l(p) t[p].l
#define r(p) t[p].r
#define sum(p) t[p].sum
#define tag1(p) t[p].tag1
#define tag2(p) t[p].tag2
#define cnt1(p) t[p].cnt1
#define cnt2(p) t[p].cnt2
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
RE int x=0,f=1;RE char ch=getc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
return x*f;
}
inline ll Read()
{
RE ll x=0,f=1;RE char ch=getc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
return x*f;
}
const int MAXN=100010;
int n,m,cnt,id,len;
int fa[MAXN],sz[MAXN],son[MAXN],d[MAXN],top[MAXN],pos[MAXN],dfn[MAXN];
int lin[MAXN],ver[MAXN<<1],nex[MAXN<<1],f[MAXN],df[MAXN];
ll a[2][2],cc[2][2];
inline void add(int x,int y)
{
ver[++len]=y;nex[len]=lin[x];lin[x]=len;
ver[++len]=x;nex[len]=lin[y];lin[y]=len;
}
struct wy//线段树
{
int l,r;
int sum;
int cnt1,cnt2;
int tag1,tag2;
}t[MAXN<<2];
struct jl//FiB
{
int f[2];
jl(){f[0]=0;f[1]=1;}
inline jl calc(ll w)
{
jl c;
a[0][0]=0;a[0][1]=a[1][0]=a[1][1]=1;
while(w)
{
if(w&1)
{
ll w1=0,w2=0;
w1=(w1+c.f[0]*a[0][0])%mod;
w2=(w2+c.f[0]*a[0][1])%mod;
w1=(w1+c.f[1]*a[1][0])%mod;
w2=(w2+c.f[1]*a[1][1])%mod;
c.f[0]=w1;c.f[1]=w2;
}
w=w>>1;
rep(0,1,i)rep(0,1,j)rep(0,1,k)
cc[i][j]=(cc[i][j]+a[i][k]*a[k][j])%mod;
rep(0,1,i)rep(0,1,j)a[i][j]=cc[i][j],cc[i][j]=0;
}
return c;
}
}s,ww;
inline void dfs(int x,int ff)
{
fa[x]=ff;d[x]=d[ff]+1;sz[x]=1;
go(x)if(tn!=ff)
{
dfs(tn,x);
if(sz[tn]>sz[son[x]])son[x]=tn;
sz[x]+=sz[tn];
}
}
inline void dp(int x,int ff)
{
top[x]=ff;dfn[x]=++id;pos[id]=x;
if(!son[x])return;
dp(son[x],ff);
go(x)if(tn!=son[x]&&tn!=fa[x])dp(tn,tn);
}
inline void build(int p,int l,int r)
{
l(p)=l;r(p)=r;
if(l==r)
{
cnt1(p)=(cnt1(p)+f[d[pos[l]]-1])%mod;
cnt2(p)=(cnt2(p)+f[d[pos[l]]])%mod;
return;
}
int mid=(l(p)+r(p))>>1;
build(zz,l,mid);
build(yy,mid+1,r);
cnt1(p)=(cnt1(zz)+cnt1(yy))%mod;
cnt2(p)=(cnt2(zz)+cnt2(yy))%mod;
}
inline void pushdown(int p)
{
tag1(zz)=(tag1(zz)+tag1(p))%mod;
tag1(yy)=(tag1(yy)+tag1(p))%mod;
tag2(zz)=(tag2(zz)+tag2(p))%mod;
tag2(yy)=(tag2(yy)+tag2(p))%mod;
sum(zz)=(sum(zz)+(ll)tag1(p)*cnt1(zz))%mod;
sum(yy)=(sum(yy)+(ll)tag1(p)*cnt1(yy))%mod;
sum(zz)=(sum(zz)+(ll)tag2(p)*cnt2(zz))%mod;
sum(yy)=(sum(yy)+(ll)tag2(p)*cnt2(yy))%mod;
tag1(p)=tag2(p)=0;
}
inline void change(int p,int l,int r)
{
if(l<=l(p)&&r>=r(p))
{
tag1(p)=(tag1(p)+ww.f[0])%mod;
tag2(p)=(tag2(p)+ww.f[1])%mod;
sum(p)=(sum(p)+(ll)ww.f[0]*cnt1(p))%mod;
sum(p)=(sum(p)+(ll)ww.f[1]*cnt2(p))%mod;
return;
}
if(tag1(p)||tag2(p))pushdown(p);
int mid=(l(p)+r(p))>>1;
if(l<=mid)change(zz,l,r);
if(r>mid)change(yy,l,r);
sum(p)=(sum(zz)+sum(yy))%mod;
}
inline int ask(int p,int l,int r)
{
if(l<=l(p)&&r>=r(p))return sum(p);
int mid=(l(p)+r(p))>>1;
if(tag1(p)||tag2(p))pushdown(p);
if(r<=mid)return ask(zz,l,r);
if(l>mid)return ask(yy,l,r);
return (ask(zz,l,r)+ask(yy,l,r))%mod;
}
inline int Task(int x,int y)
{
int fx=top[x],fy=top[y];
int ans=0;
while(fx!=fy)
{
if(d[fx]<d[fy])swap(x,y),swap(fx,fy);
ans=(ans+ask(1,dfn[fx],dfn[x]))%mod;
x=fa[fx];fx=top[x];
}
if(d[x]<d[y])swap(x,y);
ans=(ans+ask(1,dfn[y],dfn[x]))%mod;
return ans;
}
int main()
{
//freopen("1.in","r",stdin);
get(n);get(m);df[1]=1;f[1]=1;
rep(2,n,i)add(i,read()),f[i]=(f[i-2]+f[i-1])%mod,df[i]=(df[i-2]-df[i-1]+mod)%mod;
dfs(1,0);dp(1,1);build(1,1,n);
rep(1,m,i)
{
char ch=getc();
while(ch!='Q'&&ch!='U')ch=getc();
if(ch=='U')
{
int get(x);ll k;k=Read()-d[x];
if(k<=0)
{
ww.f[0]=df[-k];
if(k==0)ww.f[1]=f[1];
else ww.f[1]=df[-(k+1)];
}
else ww=s.calc(k);
change(1,dfn[x],dfn[x]+sz[x]-1);
}
else put(Task(read(),read()));
}
return 0;
}