有换父亲,考虑用维护
考虑利用斐波那契数列通项公式
由于在模下没有二次剩余
考虑维护一个模意义下的虚数
而且其实只用维护,另一半把虚部系数取反就是了
发现操作四其实只需要维护前缀积的和,后缀积的和,所有子区间的积的和,区间积就可以维护了
对于操作2,可以发现覆盖后那几个东西也都可以维护
具体就是一个等比数列求和
子区间的积的和就是等比数列求和后加起来再做一个等比数列求和就可以了
还有就是求这样一个东西的逆元
用,前面是一个实数就可以做了
#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ob==ib)?EOF:*ib++;
}
inline int read(){
char ch=gc();
int res=0,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;
}
#define ll long long
#define re register
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define cs const
#define bg begin
const int mod=998244353;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline void Add(int &a,int b){a=add(a,b);}
inline int dec(int a,int b){return a>=b?a-b:a-b+mod;}
inline void Dec(int &a,int b){a=dec(a,b);}
inline int mul(int a,int b){return 1ll*a*b>=mod?1ll*a*b%mod:a*b;}
inline void Mul(int &a,int b){a=mul(a,b);}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,a=mul(a,a))(b&1)?(res=mul(res,a)):0;return res;}
inline void ex_gcd(int a,int b,int &x,int &y){
if(!b){x=1,y=0;return ;}ex_gcd(b,a%b,y,x);y-=a/b*x;
}
struct Map{
static cs int magic=1898579;
int key[magic],val[magic];
Map(){memset(key,-1,sizeof key);}
int locate(int k)cs{
int h=k%magic;
while(key[h]!=-1&&key[h]!=k)h=h+1==magic?0:h+1;
return h;
}
int &operator[](int k){
int h=locate(k);
if(key[h]==-1){
key[h]=k;val[h]=0;
}
return val[h];
}
bool count(int k)cs{return key[locate(k)]==k;}
}iv;
inline int Inv(int a){
if(!a)return 1;
if(iv.count(a))return iv[a];
int x,y;ex_gcd(a,mod,x,y);
return iv[a]=(x%mod+mod)%mod;
}
inline void chemx(int &a,int b){a<b?a=b:0;}
inline void chemn(int &a,int b){a>b?a=b:0;}
cs int inv2=ksm(2,mod-2);
struct plx{
int x,y;
plx(int _x=0,int _y=0):x(_x),y(_y){}
friend inline plx operator +(cs plx &a,cs plx &b){
return plx(add(a.x,b.x),add(a.y,b.y));
}
friend inline plx operator +(cs plx &a,cs int &b){
return plx(add(a.x,b),a.y);
}
friend inline plx operator -(cs plx &a,cs plx &b){
return plx(dec(a.x,b.x),dec(a.y,b.y));
}
friend inline plx operator -(cs plx &a,cs int &b){
return plx(dec(a.x,b),a.y);
}
friend inline plx operator *(cs plx &a,cs plx &b){
return plx((1ll*a.x*b.x+5ll*a.y*b.y)%mod,(1ll*a.x*b.y+1ll*a.y*b.x)%mod);
}
friend inline plx operator *(cs plx &a,cs int &b){
return plx(mul(a.x,b),mul(a.y,b));
}
};
cs plx bas=plx(inv2,inv2);
inline plx ksm(plx a,int b){
plx res(1,0);
for(;b;b>>=1,a=a*a)if(b&1)res=res*a;
return res;
}
inline plx Inv(plx a){
return plx(a.x,mod-a.y)*Inv(((1ll*a.x*a.x-5ll*a.y*a.y)%mod+mod)%mod);
}
cs int N=100005;
plx a[N];
int n,m,fa[N];
namespace Lct{
struct node{
plx v,pre,suf,s;
friend inline node operator *(cs node &a,cs node &b){
node c;
c.s=a.s+b.s+a.suf*b.pre;
c.pre=a.pre+a.v*b.pre;
c.suf=a.suf*b.v+b.suf;
c.v=a.v*b.v;
return c;
}
};
node val[N];
int fa[N],son[N][2],siz[N],rev[N],cov[N];
#define lc(u) son[u][0]
#define rc(u) son[u][1]
inline void initval(int u){
val[u].v=val[u].pre=val[u].suf=val[u].s=a[u],siz[u]=1;
}
inline void pushup(int u){
initval(u);
siz[u]=siz[lc(u)]+siz[rc(u)]+1;
if(lc(u))val[u]=val[lc(u)]*val[u];
if(rc(u))val[u]=val[u]*val[rc(u)];
}
inline void pushcov(int u,int k){
plx x=ksm(bas,k),iv=Inv(x-1);
a[u]=x,val[u].v=ksm(x,siz[u]);
val[u].pre=val[u].suf=(val[u].v*x-x)*iv;
val[u].s=((val[u].v*x*x-x*x)*iv-x*siz[u])*iv;
cov[u]=k;
}
inline void pushrev(int u){
swap(lc(u),rc(u));
swap(val[u].pre,val[u].suf),rev[u]^=1;
}
inline void pushdown(int u){
if(rev[u]){
if(lc(u))pushrev(lc(u));
if(rc(u))pushrev(rc(u));
rev[u]=0;
}
if(cov[u]){
if(lc(u))pushcov(lc(u),cov[u]);
if(rc(u))pushcov(rc(u),cov[u]);
cov[u]=0;
}
}
inline bool isrt(int u){
if(!fa[u])return 1;
return lc(fa[u])!=u&&rc(fa[u])!=u;
}
inline bool isrc(int u){
return rc(fa[u])==u;
}
inline void rotate(int v){
int u=fa[v],z=fa[u];
int t=rc(u)==v;
fa[v]=z;
if(!isrt(u))son[z][rc(z)==u]=v;
fa[son[v][t^1]]=u,son[u][t]=son[v][t^1];
son[v][t^1]=u,fa[u]=v;
pushup(u),pushup(v);
}
int stk[N],top;
inline void splay(int u){
stk[top=1]=u;
for(int v=u;!isrt(v);v=fa[v])stk[++top]=fa[v];
for(int i=top;i;i--)pushdown(stk[i]);
while(!isrt(u)){
if(!isrt(fa[u]))
isrc(u)==isrc(fa[u])?rotate(fa[u]):rotate(u);
rotate(u);
}
}
inline void access(int u){
for(int v=0;u;v=u,u=fa[u]){
splay(u),rc(u)=v;
if(v)fa[v]=u;
pushup(u);
}
}
inline void makert(int u){
access(u),splay(u),pushrev(u);
}
inline void link(int u,int v){
makert(u),splay(v),fa[u]=v,pushup(v);
}
inline void cut(int u,int v){
makert(u),access(v),splay(v);
lc(v)=fa[u]=0;pushup(v);
}
inline int query(int u,int v){
makert(u);
access(v);
splay(v);
plx now=val[v].s;
return mul(2,now.y);
}
inline void cover(int u,int v,int k){
makert(u),access(v),splay(v);
pushcov(v,k);
}
}
int main(){
#ifdef Stargazer
freopen("lx.cpp","r",stdin);
#endif
n=read(),m=read();
for(int i=1;i<=n;i++){
int k=read();
a[i]=ksm(bas,k);
Lct::initval(i);
}
for(int i=2;i<=n;i++)Lct::fa[i]=fa[i]=read();
while(m--){
int op=read();
if(op==1){
int u=read(),v=read();
Lct::cut(u,fa[u]),Lct::link(u,v),fa[u]=v;
}
if(op==2){
int u=read(),v=read(),k=read();
Lct::cover(u,v,k);
}
if(op==3){
int u=read();
Lct::makert(u);plx now=a[u];
cout<<mul(2,now.y)<<'
';
}
if(op==4){
int u=read(),v=read();
cout<<Lct::query(u,v)<<'
';
}
}
}