树状数组+欧拉降幂
题目描述
给一个长为n的序列,m次操作,每次操作:
1.区间[l,r][l,r][l,r]加xxx
2.对于区间[l,r][l,r][l,r],查询a[l]a[l+1]a[l+2]......a[l]^{a[l+1]^{a[l+2]......}}a[l]a[l+1]a[l+2]......modmodmod ppp,一直到aaa-rrr
请注意每次的模数不同。
输入描述:
第一行两个整数 n,m 表示序列长度和操作数
接下来一行,n个整数,表示这个序列
接下来m行,可能是以下两种操作之一:
操作1:区间[l,r]加上 x
操作2:查询区间[l,r]的那个式子mod p的值
输出描述:
对于每个询问,输出一个数表示答案
备注:
n , m <= 500000
序列中每个数在 [1,2e9] 内,x <= 2e9 , p <= 2e7
#include<bits/stdc++.h>
#include<tr1/unordered_map>
typedef long long ll;
using namespace std;
const int maxn=2e7+9;
const int MAX=1e5+9;
bool vis[maxn];
int cnt,prim[maxn],phi[maxn],n;
ll a[maxn];
typedef pair<ll,int>P;
inline int lowbit(int x)
{
return x&(-x);
}
inline void update(int l,int k)
{
while(l<=n)
{
a[l]+=k;
l+=lowbit(l);
}
}
inline ll query(int l)
{
ll ans=0;
while(l)
{
ans+=a[l];
l-=lowbit(l);
}
return ans;
}
inline ll read()
{
ll res=0;
char c=getchar();
while(!isdigit(c))c=getchar();
while(isdigit(c))res=(res<<1)+(res<<3)+c-48,c=getchar();
return res;
}
inline void init()
{
ll i,j;
vis[1]=phi[1]=1;
for(i=2;i<=maxn-9;i++)
{
if(!vis[i])
{
prim[++cnt]=i;
phi[i]=i-1;
}
for(j=1;j<=cnt&&i*prim[j]<=maxn-9;++j)
{
vis[i*prim[j]]=1;
if(i%prim[j]==0)
{
phi[i*prim[j]]=phi[i]*prim[j];break;
}
phi[i*prim[j]]=phi[i]*(prim[j]-1);
}
}
}
P Pow(ll a,ll b,ll p)
{
ll ans=1,temp=1,i;
int flag=0;
for(i=1;i<=b;i++)
{
temp=temp*a;
if(temp>=p)
{
flag=1;break;
}
}
a%=p;
while(b)
{
if(b&1)ans=ans*a%p;
a=a*a%p;
b>>=1;
}
return P(ans,flag);
}
inline P getans(ll l,ll r,ll p)
{
ll a=query(l);
if(a==1||l==r||p==1)return P(a%p,a>=p?1:0);
P b=getans(l+1,r,phi[p]);
if(b.second)b.first+=phi[p];
return Pow(a,b.first,p);
}
int main()
{
int m,i;
scanf("%d%d",&n,&m);
init();
for(i=1;i<=n;i++)
{
ll a;
scanf("%lld",&a);
update(i,a);
update(i+1,-a);
}
while(m--)
{
int opt;
ll l,r,x;
scanf("%d%lld%lld%lld",&opt,&l,&r,&x);
if(opt==1)
{
update(l,x);
update(r+1,-x);
}
else
{
printf("%lld\n",getans(l,r,x).first);
}
}
}
欢迎加我qq1165750856一起玩呀~

浙公网安备 33010602011771号