【XSY3938】平方问题(线段树)
题面
题解
记 \(p=998244353\),那么 \(a^{p-1}\equiv 1\pmod p\)。(\(\gcd(a,p)=1\))
那么 \(a^b\equiv a^{b\bmod (p-1)}\pmod p\)。
题目的操作相当于每次把一个数的指数乘上 \(2\),那么每个数都能表示成 \(a^{2^x}\) 的形式。(初始时 \(x=0\))
打表找 \(2^x\bmod 998244352\) 的循环节,发现从 \(2^{23}\) 开始,每 \(24\) 位循环一次,即 \(2^{23}\equiv 2^{47}\pmod{p-1},2^{24}\equiv 2^{48}\pmod{p-1},\cdots\)。
那么对于每个数的修改,前 \(23\) 次我们暴力跑,后面的我们就在线段树上对于每一个区间维护一个大小为 \(24\) 的环,修改一次我们就把环转一格即可。
代码如下:
#include<bits/stdc++.h>
#define N 200010
using namespace std;
namespace modular
{
const int mod=998244353;
inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
}using namespace modular;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^'0');
ch=getchar();
}
return x*f;
}
int n,q,a[N],tim[N];
int f[N<<2][24];
int lazy[N<<2];
bool ok[N<<2];
void up(int k)
{
for(int i=0;i<24;i++) f[k][i]=add(f[k<<1][i],f[k<<1|1][i]);
ok[k]=(ok[k<<1]&ok[k<<1|1]);
}
void build(int k,int l,int r)
{
if(l==r)
{
f[k][0]=read();
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
up(k);
}
void turn(int k,int tim)
{
static int b[24];
for(int i=0;i<24;i++) b[i]=f[k][i];
for(int i=0;i<24;i++) f[k][i]=b[(i+tim)%24];
}
void downn(int k,int tim)
{
turn(k,tim);
lazy[k]=(lazy[k]+tim)%24;
}
void down(int k)
{
if(lazy[k])
{
downn(k<<1,lazy[k]);
downn(k<<1|1,lazy[k]);
lazy[k]=0;
}
}
void update(int k,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr&&ok[k])
{
downn(k,1);
return;
}
if(l==r)
{
f[k][0]=mul(f[k][0],f[k][0]);
tim[l]++;
if(tim[l]==23)
{
ok[k]=1;
for(int i=1;i<24;i++)
f[k][i]=mul(f[k][i-1],f[k][i-1]);
}
return;
}
down(k);
int mid=(l+r)>>1;
if(ql<=mid) update(k<<1,l,mid,ql,qr);
if(qr>mid) update(k<<1|1,mid+1,r,ql,qr);
up(k);
}
int query(int k,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr) return f[k][0];
down(k);
int mid=(l+r)>>1,ans=0;
if(ql<=mid) ans=add(ans,query(k<<1,l,mid,ql,qr));
if(qr>mid) ans=add(ans,query(k<<1|1,mid+1,r,ql,qr));
return ans;
}
int main()
{
n=read(),q=read();
build(1,1,n);
while(q--)
{
int opt=read(),l=read(),r=read();
if(opt==1) update(1,1,n,l,r);
else printf("%d\n",query(1,1,n,l,r));
}
return 0;
}
/*
3 3
1 2 3
2 1 3
1 1 2
2 2 3
*/