题目大意:给定一个序列,两种操作:
1)Q l r 询问[l,r]的和,对329701061取模。
2)C l r 将[l,r]内每个数变成其立方。
n,q<=100000。
题解:一眼线段树对吧。
听教练说是道简单的线段树,但我又傻又笨又手残,不知道咋维护每个数的立方,就去写分块了。
但是还能注意到一个问题:为啥这个模数看起来这么奇怪啊?肯定有某种奇异的规律,打表试试。
打了1~100的表后发现规律:一个数立方48次以后就会回到原数。
于是可以分块了。
先维护每个数立方1~48次各是多少,块内存这一块的和就行了。
先考虑询问:块外的暴力,块内的直接加。
但是修改操作会让这一段序列里的数立方次数不一样啊,我因此差点GG在考场上。
后来蹲坑时想到了一个乱搞的方法:每次修改完后我都把这个数的当前立方次数旋转到第一个,那么每次我只用看第一个就行了嘛,问题解决。
说起来可能有点绕,看代码应该能更清楚一点。
代码:
#include<bits/stdc++.h>
#define maxn 100005
#define K 48
#define mod 329701061
using namespace std;
typedef long long LL;
LL read()
{
char c;LL sum=0,f=1;c=getchar();
while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0' && c<='9'){sum=sum*10+c-'0';c=getchar();}
return sum*f;
}
int n,q,m,tot;
int bel[maxn],l[maxn],r[maxn],cnt[maxn];
LL num[maxn][50],block[maxn][48];
LL temp[50];
void init()
{
for(int i=1;i<=n;i++)
for(int j=1;j<K;j++)
num[i][j]=num[i][j-1]*num[i][j-1]%mod*num[i][j-1]%mod;
for(int i=1;i<=tot;i++)
for(int j=0;j<K;j++)
for(int k=l[i];k<=r[i];k++)
{
block[i][j]+=num[k][j];
if(block[i][j]>=mod)
block[i][j]-=mod;
}
}
void rotate(int id,int x)
{
if(!x) return;
for(int i=0;i<x;i++)temp[i]=num[id][i];
for(int i=x;i<K;i++)num[id][i-x]=num[id][i];
for(int i=0;i<x;i++)num[id][i+K-x]=temp[i];
}
void update(int b)
{
for(int i=0;i<K;i++)
{
block[b][i]=0;
for(int j=l[b];j<=r[b];j++)
{
block[b][i]+=num[j][i];
if(block[b][i]>=mod)
block[b][i]-=mod;
}
}
}
void add(int x,int y)
{
if(bel[x]==bel[y])
{
for(int i=l[bel[x]];i<x;i++)
rotate(i,cnt[bel[x]]);
for(int i=y+1;i<=r[bel[y]];i++)
rotate(i,cnt[bel[x]]);
cnt[bel[x]]++;
if(cnt[bel[x]]==K)
cnt[bel[x]]=0;
for(int i=x;i<=y;i++)
rotate(i,cnt[bel[x]]);
cnt[bel[x]]=0;
update(bel[x]);
return;
}
if(x==l[bel[x]]) x=bel[x];
else
{
for(int i=l[bel[x]];i<x;i++)
rotate(i,cnt[bel[x]]);
cnt[bel[x]]++;
if(cnt[bel[x]]==K)
cnt[bel[x]]=0;
for(int i=x;i<=r[bel[x]];i++)
rotate(i,cnt[bel[x]]);
cnt[bel[x]]=0;
update(bel[x]);
x=bel[x]+1;
}
if(y==r[bel[y]]) y=bel[y];
else
{
for(int i=y+1;i<=r[bel[y]];i++)
rotate(i,cnt[bel[y]]);
cnt[bel[y]]++;
if(cnt[bel[y]]==K)
cnt[bel[y]]=0;
for(int i=l[bel[y]];i<=y;i++)
rotate(i,cnt[bel[y]]);
cnt[bel[y]]=0;
update(bel[y]);
y=bel[y]-1;
}
for(int i=x;i<=y;i++)
{
cnt[i]++;
if(cnt[i]==K)
cnt[i]=0;
}
}
LL query(int x,int y)
{
LL ans=0;
if(bel[x]==bel[y])
{
for(int i=x;i<=y;i++)
{
ans+=num[i][cnt[bel[x]]];
if(ans>=mod) ans-=mod;
}
return ans;
}
if(x==l[bel[x]]) x=bel[x];
else
{
for(int i=x;i<=r[bel[x]];i++)
{
ans+=num[i][cnt[bel[x]]];
if(ans>=mod)
ans-=mod;
}
x=bel[x]+1;
}
if(y==r[bel[y]])
y=bel[y];
else
{
for(int i=l[bel[y]];i<=y;i++)
{
ans+=num[i][cnt[bel[y]]];
if(ans>=mod) ans-=mod;
}
y=bel[y]-1;
}
for(int i=x;i<=y;i++)
{
ans+=block[i][cnt[i]];
if(ans>=mod)
ans-=mod;
}
return ans;
}
int main()
{
n=read();
for (int i=1;i<=n;i++)
num[i][0]=read();
m=n/floor(sqrt(n*48));
if(!m) m=1;
tot=(n-1)/m+1;
for(int i=1;i<=n;i++)
{
bel[i]=(i-1)/m+1;
if(bel[i]!=bel[i-1])
r[bel[i-1]]=i-1,l[bel[i]]=i;
}
r[tot]=n;
init();
q=read();
while(q--)
{
char c=getchar();
while(c!='C'&& c!='Q') c=getchar();
int x=read(),y=read();
if(x>y) swap(x,y);
if(c=='C') add(x,y);
if(c=='Q') printf("%lld\n",query(x,y));
}
}