【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
*/
posted @ 2022-10-30 14:26  ez_lcw  阅读(14)  评论(0编辑  收藏  举报