题目大意:设
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(k1−1,k2−1)+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)=(M−1)k−1−FM(k−1),因此矩乘求某一项即可。
#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;
}