题意:
支持区间平方
(modp)
,区间求和(
p≤10000
且为质数)。
题解:
每个数在平方意义下有循环节,且所有循环节的
gcd≤70
,那么每个点维护
70
个数就好了。
在进入循环前会有一段不循环的区域(呈 ρ 形),对于之前的直接暴力修改+并查集维护即可。
#include<bits/stdc++.h>
using namespace std;
inline int rd(){
char ch=getchar();int i=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();}
return i*f;
}
inline void W(int x){
static int buf[50];
if(!x){putchar('0');return;}
if(x<0){putchar('-');x=-x;}
while(x){buf[++buf[0]]=x%10;x/=10;}
while(buf[0])putchar(buf[buf[0]--]+'0');
}
const int LIM=80;
const int N=1e5+50;
int n,m,p,v[N][LIM],nst[N],st[N],vis[N],pos[N],bg[N],R[N],vt;
inline int gcd(int x,int y){return y?(gcd(y,x%y)):x;}
inline int getr(int x){return (R[x]==x)?x:(R[x]=getr(R[x]));}
struct node{
int cir[LIM],nowst,sze,tag;
node *lc,*rc;
node(){
nowst=1;sze=1;tag=0;
}
inline int getnxt(int v){
return (v==sze)?1:v+1;
}
inline void push(int v){
tag+=v;
(nowst+=v)%=sze;
if(!nowst)nowst=sze;
}
}Pool[N*4],*rt,*pool=Pool;
inline void build(node *&now,int l,int r){
now=++pool;
if(l==r)return;
int mid=(l+r)>>1;
build(now->lc,l,mid);
build(now->rc,mid+1,r);
}
inline void pushdown(node *now){
if(!now->tag)return;
now->lc->push(now->tag);now->rc->push(now->tag);
now->tag=0;
}
inline void upt(node *now){
now->sze=now->lc->sze*now->rc->sze/gcd(now->lc->sze,now->rc->sze);
now->tag=0;now->nowst=1;int p1=now->lc->nowst,p2=now->rc->nowst;
for(int i=1;i<=now->sze;i++){
now->cir[i]=now->lc->cir[p1]+now->rc->cir[p2];
p1=now->lc->getnxt(p1);
p2=now->rc->getnxt(p2);
}
}
inline void insert(node *now,int l,int r,int pos){
if(l==r){
now->sze=st[pos]-bg[pos]+1;
for(int i=1;i<=now->sze;++i)now->cir[i]=v[pos][bg[pos]+i-1];
now->tag=0;now->nowst=1;
return;
}
pushdown(now);int mid=(l+r)>>1;
if(pos<=mid)insert(now->lc,l,mid,pos);
else insert(now->rc,mid+1,r,pos);
upt(now);
}
inline void modify(node *now,int l,int r,int L,int R){
if(L<=l&&r<=R){
now->push(1);
return;
}
pushdown(now);int mid=(l+r)>>1;
if(R<=mid)modify(now->lc,l,mid,L,R);
else if(L>mid)modify(now->rc,mid+1,r,L,R);
else modify(now->lc,l,mid,L,R),modify(now->rc,mid+1,r,L,R);
upt(now);
}
inline int query(node *now,int l,int r,int L,int R){
if(L<=l&&r<=R)return now->cir[now->nowst];
pushdown(now);int mid=(l+r)>>1,rs=0;
if(R<=mid)rs=query(now->lc,l,mid,L,R);
else if(L>mid)rs=query(now->rc,mid+1,r,L,R);
else return rs=query(now->lc,l,mid,L,R)+query(now->rc,mid+1,r,L,R);
return upt(now),rs;
}
inline int query(int l,int r){
int rs=query(rt,1,n,l,r);
for(int i=getr(l);i<=r;i=getr(i+1)){
rs+=v[i][nst[i]];
}
return rs;
}
inline void modify(int l,int r){
modify(rt,1,n,l,r);
for(int i=getr(l);i<=r;i=getr(i+1)){
++nst[i];
if(nst[i]==bg[i]){
insert(rt,1,n,i);
R[i]=i+1;
}
}
}
int main(){
n=rd(),m=rd(),p=rd();
build(rt,1,n);
for(int i=1;i<=n+1;i++)R[i]=i;
for(int i=1;i<=n;i++){
int x=rd()%p;++vt;
while(vis[x]!=vt){
v[i][++st[i]]=x;
pos[x]=st[i];
vis[x]=vt;
x=1ll*x*x%p;
}bg[i]=pos[x];
nst[i]=1;
if(nst[i]==bg[i])insert(rt,1,n,i),R[i]=i+1;
}
for(int i=1;i<=m;i++){
int op=rd(),l=rd(),r=rd();
if(op==0){
modify(l,r);
}else W(query(l,r)),putchar('\n');
}
}