Elephant - 平衡树 - 矩阵乘法

题目大意:设 F M ( k ) F_M(k) FM(k)表示一张M个点的无向完全图从1走k步回到自己的方案数。给定序列 { a n } \{a_n\} {an},支持:区间加,区间翻转,区间求 F M ( a i ) F_M(a_i) FM(ai) gcd ⁡ \gcd gcd。其中M是固定的(输入的常数)。
题解:通过观察发现 gcd ⁡ ( F M ( k 1 ) , F M ( k 2 ) ) = F M ( gcd ⁡ ( k 1 − 1 , k 2 − 1 ) + 1 ) \gcd \left(F_M(k_1),F_M(k_2)\right)=F_M(\gcd(k_1-1,k_2-1)+1) gcd(FM(k1),FM(k2))=FM(gcd(k11,k21)+1)。因此维护区间加区间翻转区间求gcd即可,这个可以通过差分后一个平衡树实现。然后显然有 F M ( k ) = ( M − 1 ) k − 1 − F M ( k − 1 ) F_M(k)=(M-1)^{k-1}-F_M(k-1) FM(k)=(M1)k1FM(k1),因此矩乘求某一项即可。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define mod 323232323
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
namespace INPUT_SPACE{
    const int BS=(1<<24)+5;char Buffer[BS],*HD,*TL;inline int gc() { if(HD==TL) TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);return (HD==TL)?EOF:*HD++; }
    inline int inn() { int x,ch;while((ch=gc())<'0'||ch>'9');x=ch^'0';while((ch=gc())>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0');return x; }
}using INPUT_SPACE::inn;
namespace OUTPUT_SPACE{
    char ss[100000*15],tt[20];int ssl,ttl;inline int Flush() { return fwrite(ss+1,sizeof(char),ssl,stdout),ssl=0,0; }
    inline int print(int x) { if(!x) ss[++ssl]='0';for(ttl=0;x;x/=10) tt[++ttl]=char(x%10+'0');for(;ttl;ttl--) ss[++ssl]=tt[ttl];return ss[++ssl]='\n'; }
}using OUTPUT_SPACE::print;using OUTPUT_SPACE::Flush;
//conclusion : ans = f[ gcd(a_i-1) + 1 ]
const int N=100010,INF=INT_MAX/2;
inline int gcd(int x,int y) { return x?gcd(y%x,x):y; }
inline int gabs(int x) { return x<0?-x:x; }
#define DimSetc inline int setc(int x,int y,int z) { return (z?rc[x]:lc[x])=y,push_up(x); }
#define DimMerge inline int _merge(int x,int y)\
{\
    if(!x||!y) return x+y;push_down(x),push_down(y);\
    if(key[x]<key[y]) return rc[x]=_merge(rc[x],y),push_up(x),x;\
    else return lc[y]=_merge(x,lc[y]),push_up(y),y;\
}
#define DimSplit inline pii split(int x,int k)\
{\
    if(!x||sz[x]<=k) return mp(x,0);pii t;push_down(x);\
    if(k<=lc[x][sz]) return t=split(lc[x],k),setc(x,t.sec,0),mp(t.fir,x);\
    else return t=split(rc[x],k-lc[x][sz]-1),setc(x,t.fir,1),mp(x,t.sec);\
}
#define DimIns inline int ins(int x) { return rt=_merge(rt,new_node(x)); }
#define DimReverse inline int _reverse(int l,int r)\
{\
    if(l>=r) return 0;pii a=split(rt,r),b=split(a.fir,l-1);\
    return rev[b.sec]^=1,rt=_merge(_merge(b.fir,b.sec),a.sec);\
}
inline int rnd() { return rand()*32767+rand(); }
struct T1{
    int rt,node_cnt,lc[N],rc[N],mn[N],val[N],sz[N],pt[N],rev[N],key[N];
    T1() { node_cnt=rt=0,mn[0]=val[0]=INF; }
    inline int push_up(int x) { return sz[x]=sz[lc[x]]+sz[rc[x]]+1,mn[x]=min(val[x],min(mn[lc[x]],mn[rc[x]])); }
    inline int update_tags(int x,int v) { return pt[x]+=v,val[x]+=v,mn[x]+=v; }
    inline int push_down(int x)
    {
        if(rev[x])
        {
            if(lc[x]) rev[lc[x]]^=1;
            if(rc[x]) rev[rc[x]]^=1;
            swap(lc[x],rc[x]),rev[x]=0;
        }
        if(pt[x])
        {
            if(lc[x]) update_tags(lc[x],pt[x]);
            if(rc[x]) update_tags(rc[x],pt[x]);
            pt[x]=0;
        }
        return 0;
    }
    inline int new_node(int v) { int x=++node_cnt;return key[x]=rnd(),val[x]=mn[x]=v,sz[x]=1,x; }
    DimSetc DimMerge DimSplit DimIns DimReverse
    inline int querymin(int l,int r)
    {
        pii a=split(rt,r),b=split(a.fir,l-1);int ans=mn[b.sec];
        return rt=_merge(_merge(b.fir,b.sec),a.sec),ans;
    }
    inline int query(int x) { return querymin(x,x); }
    inline int update(int l,int r,int k)
    {
        pii a=split(rt,r),b=split(a.fir,l-1);update_tags(b.sec,k);
        return rt=_merge(_merge(b.fir,b.sec),a.sec);
    }
}t1;
struct T2{
    int rt,node_cnt,lc[N],rc[N],val[N],g[N],sz[N],rev[N],key[N];
    inline int push_up(int x) { return sz[x]=sz[lc[x]]+sz[rc[x]]+1,g[x]=gcd(val[x],gcd(g[lc[x]],g[rc[x]])); }
    inline int push_down(int x)
    {
        if(rev[x])
        {
            if(lc[x]) rev[lc[x]]^=1;
            if(rc[x]) rev[rc[x]]^=1;
            swap(lc[x],rc[x]),rev[x]=0;
        }
        return 0;
    }
    inline int new_node(int v) { int x=++node_cnt;return key[x]=rnd(),val[x]=g[x]=gabs(v),sz[x]=1,x; }
    DimSetc DimMerge DimSplit DimIns DimReverse
    inline int query(int l,int r)
    {
        pii a=split(rt,r),b=split(a.fir,l-1);int ans=g[b.sec];
        return rt=_merge(_merge(b.fir,b.sec),a.sec),ans;
    }
    inline int update(int x,int v)
    {
        pii a=split(rt,x),b=split(a.fir,x-1);g[b.sec]=val[b.sec]=gabs(v);
        return rt=_merge(_merge(b.fir,b.sec),a.sec);
    }
}t2;
namespace F_space{
    int a[3][3],ans[3][3],w[3][3];
    inline int tms(int a[3][3],int b[3][3],int c[3][3])
    {
        rep(i,1,2) rep(j,1,2) w[i][j]=int(((lint)a[i][1]*b[1][j]+(lint)a[i][2]*b[2][j])%mod);
        rep(i,1,2) rep(j,1,2) c[i][j]=w[i][j];return 0;
    }
    inline int fast_pow(int a[3][3],int k,int ans[3][3])
    {
        ans[1][1]=ans[2][2]=1,ans[1][2]=ans[2][1]=0;
        for(;k;k>>=1,tms(a,a,a)) if(k&1) tms(ans,a,ans);return 0;
    }
    inline int F(int m,int k)
    {
        if(k==0) return 1;if(k==1) return 0;
        a[1][1]=mod-1,a[1][2]=1,a[2][1]=0,a[2][2]=m;
        fast_pow(a,k,ans);
        int res=ans[1][1]+ans[1][2];
        return res>=mod?res-mod:res;
    }
}
int a[N];
int main()
{
    inn();int m=(inn()-1)%mod,n=inn(),q=inn();
    rep(i,1,n) a[i]=inn();
    rep(i,1,n) t1.ins(a[i]-1);
    rep(i,1,n-1) t2.ins(a[i+1]-a[i]);
    while(q--)
    {
        int tp=inn(),l=inn(),r=inn();
        if(tp==1)
        {
            if(t1.querymin(l,r)<0) { print(1);continue; }
            int x=gcd(t1.query(l),t2.query(l,r-1));
            print(F_space::F(m,x+1));
        }
        if(tp==2)
        {
            t1._reverse(l,r),t2._reverse(l,r-1);
            if(l>1) t2.update(l-1,t1.query(l-1)-t1.query(l));
            if(r<n) t2.update(r,t1.query(r)-t1.query(r+1));
        }
        if(tp==3)
        {
            int k=inn();t1.update(l,r,k);
            if(l>1) t2.update(l-1,t1.query(l-1)-t1.query(l));
            if(r<n) t2.update(r,t1.query(r)-t1.query(r+1));
        }
    }
    return Flush(),0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值