题面见校内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;
}