题意:
单点更新,区间求和,求和操作和普通的求和不一样,如果我们要求2~5的和,sum=1*f[5]+b*f[4]+b*b*f[3]+b*b*b*f[2],输出每个询问操作的答案,同时答案要模p。
思路:
我们可以在操作的时候直接给每个位置的数字成上b的多少次幂,例如如果是五个数字,我们插入f1时,我们不插入f1,而是插入f1*b*b*b*b,插入f2时,我们插入f2*b*b*b,这样,询问的时候我们就可以直接区间求和,再除以一个b的多少次幂。同时要注意,除法取模要求逆元,计算b的次幂的时候要用快速幂,被红书的快速幂坑了。。。它的那个取模不够彻底。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
using namespace std;
long long _b,_p,_l,_n;
long long pow_mod(long long a,long long i,long long n)
{
if(i==0)
return 1%n;
int temp=pow_mod(a%n,i>>1,n)%n;
temp=(temp%n*temp%n)%n;
if(i&1)
temp=(long long)temp*a%n;
return temp;
}
long long extend_gcd(long long a,long long b,long long &x,long long &y)
{
if(a==0&&b==0) return -1;//无最大公约数
if(b==0){x=1;y=0;return a;}
long long d=extend_gcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
long long mod_reverse(long long a,long long n)
{
long long x,y;
long long d=extend_gcd(a,n,x,y);
if(d==1) return (x%n+n)%n;
else return -1;
}
const long long maxn=100005;
long long Tree[maxn+10];
inline long long lowbit(long long x)
{
return x&(-x);
}
void add(long long x,long long value)
{
for(long long i=x;i<=maxn;i+=lowbit(i))
{
Tree[i]+=value;
Tree[i]%=_p;
}
}
long long get(long long x)
{
long long sum=0;
for(long long i=x;i;i-=lowbit(i))
{
sum+=Tree[i];
sum%=_p;
}
return (sum);
}
int main()
{
//cout << pow_mod(2, 10, 1000000) << endl;
while(scanf("%lld%lld%lld%lld",&_b,&_p,&_l,&_n)!=EOF)
{
memset(Tree,0,sizeof Tree);
if(!_b&&!_p&&!_l&&!_n)
return 0;
for(long long i=1;i<=_n;i++)
{
char s[3];
long long x,y;
scanf("%s%lld%lld",s,&x,&y);
if(s[0]=='E')
{
y%=_p;
long long tmp=(get(x)-get(x-1)+_p)%_p;
// printf("tmp=%lld\n",tmp);
// printf("lala=%lld\n",(y*pow_mod(_b,_l-x,_p)%_p-tmp+_p)%_p);
add(x,(y*pow_mod(_b%_p,_l-x,_p)%_p-tmp+_p)%_p);
//add(x,y);
}
else
{
long long ans=(get(y)%_p-get(x-1)%_p+_p)%_p;
// printf("---------------- %lld %lld \n",get(y),get(x-1));
// printf("chu=%lld\n",pow_mod(_b%_p,_l-y,_p));
// printf("ans=%lld\n",ans);
ans%=_p;
long long ni=mod_reverse(pow_mod(_b%_p,_l-y,_p),_p);
ni%=_p;
ans*=ni;
printf("%lld\n",ans%_p);
}
}
printf("-\n");
}
return 0;
}