链接:https://ac.nowcoder.com/acm/problem/17190
来源:牛客网
题目描述
给一个长为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); } } }