• 【NOIp2019模拟】T2—水题(LCT+斐波那契数列)


    传送门

    有换父亲,考虑用LCTLCT维护
    考虑利用斐波那契数列通项公式

    fi=(1+52)i(152)i5f_i=frac{(frac{1+sqrt 5}2)^i-(frac{1-sqrt5}2)^i}{sqrt 5}
    由于55在模998244353998244353下没有二次剩余
    考虑维护一个模意义下的虚数
    而且其实只用维护1+51+sqrt 5,另一半把虚部系数取反就是了
    发现操作四其实只需要维护前缀积的和,后缀积的和,所有子区间的积的和,区间积就可以维护了

    对于操作2,可以发现覆盖后那几个东西也都可以维护
    具体就是一个等比数列求和
    子区间的积的和就是等比数列求和后加起来再做一个等比数列求和就可以了

    还有就是求a+b5a+bsqrt 5这样一个东西的逆元
    (a25b2)=(a+b5)(ab5)(a^2-5b^2)=(a+bsqrt 5)(a-bsqrt 5),前面是一个实数就可以做了

    #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)<<'
    ';
    		}
    	}
    }
    
  • 相关阅读:
    SPSS时间序列:频谱分析
    PureBasic—数控编辑框与调节块和进度条
    DELPHI2007 安装ACTIVEX插件的方法
    C++ builder的文件操作
    C++动态数组
    excel快速复制大量公式的方法
    Delphi XE5 如何与其他版本共存
    PureBasic 集成Form设计器的使用
    VS C++ 从一个窗口创建另一个窗口
    ENVI 5.0 Beta 体验——影像数据的显示
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/12328587.html
Copyright © 2020-2023  润新知