题目大意:给你一个序列,求出指定区间的(l<=i<=r) mod 1000777 的值
还复习了欧拉函数以及线性筛逆元
考虑欧拉函数的的性质,(l<=i<=r),等价于 (p[j]是区间内所有出现过的质数)
那么考虑找出区间内所有出现过的质数,这思路和HH的项链是不是很像??
由于此题强制在线,所以把树状数组替换成了主席树而已
原来我以前写的主席树一直都是错的......还好推出了我原来错误代码的反例
在继承上一个树的信息时,注意不要破坏现在的树
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
#define il inline
#define N 50010
#define maxn 1000000
#define mod 1000777
using namespace std;
int n,q,ctp,tot;
int root[N];
int pr[maxn+100],use[maxn+100],lst[maxn+100];
ll a[N],inv[mod+100],nxt[maxn+100];
struct Seg{ll sum;int ls,rs;}seg[N*60]; //re
void prime_inv()
{
for(int i=2;i<=maxn;i++)
{
if(!use[i])
pr[++ctp]=i,nxt[i]=i;
for(int j=1;j<=ctp&&i*pr[j]<=maxn;j++){
use[i*pr[j]]=1,nxt[i*pr[j]]=pr[j];
if(i%pr[j]==0) break;
}
}
inv[0]=inv[1]=1;
for(ll i=2;i<mod;i++)
inv[i]=(mod-mod/i)*inv[mod%i]%mod;
}
ll gc()
{
ll ret=0,fh=1;char p=getchar();
while(p<'0'||p>'9') {if(p=='-')fh=-1;p=getchar();}
while(p>='0'&&p<='9') {ret=(ret<<3)+(ret<<1)+p-'0';p=getchar();}
return ret*fh;
}
il void pushup(int rt){seg[rt].sum=(seg[seg[rt].ls].sum*seg[seg[rt].rs].sum)%mod;}
void build(int l,int r,int rt)
{
seg[rt].sum=1;
if(l==r)return;
int mid=(l+r)>>1;
seg[rt].ls=++tot,build(l,mid,tot);
seg[rt].rs=++tot,build(mid+1,r,tot);
}
void update(int x,int l,int r,int rt1,int rt2,ll w)
{
if(l==r) {seg[rt2].sum=(seg[rt2].sum*w)%mod;return;}
int mid=(l+r)>>1;
if(x<=mid)
{
if(!seg[rt2].ls||seg[rt1].ls==seg[rt2].ls){
seg[rt2].ls=++tot,seg[seg[rt2].ls].sum=seg[seg[rt1].ls].sum;
if(!seg[rt2].rs)
seg[rt2].rs=seg[rt1].rs;
}
update(x,l,mid,seg[rt1].ls,seg[rt2].ls,w);
}else{
if(!seg[rt2].rs||seg[rt1].rs==seg[rt2].rs){
seg[rt2].rs=++tot,seg[seg[rt2].rs].sum=seg[seg[rt1].rs].sum;
if(!seg[rt2].ls)
seg[rt2].ls=seg[rt1].ls;
}
update(x,mid+1,r,seg[rt1].rs,seg[rt2].rs,w);
}
pushup(rt2);
}
ll query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R) return seg[rt].sum;
int mid=(l+r)>>1;ll ans=1;
if(L<=mid) ans*=query(L,R,l,mid,seg[rt].ls),ans%=mod;
if(R>mid) ans*=query(L,R,mid+1,r,seg[rt].rs),ans%=mod;
return ans;
}
int main()
{
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++) a[i]=gc();
prime_inv();
root[0]=++tot;
build(1,n,1);
ll x,p,w;
for(int i=1;i<=n;i++)
{
x=a[i],w=a[i],root[i]=++tot;
while(x!=1){
p=nxt[x];
if(lst[p])
update(lst[p],1,n,root[i-1],root[i],(inv[p-1]*p)%mod);
lst[p]=i;
x/=p,w=((w*(p-(ll)1)%mod)*inv[p])%mod;
while(x%p==0) x/=p;
}
update(i,1,n,root[i-1],root[i],w);
}
ll l,r,ans=0;
for(int i=1;i<=q;i++)
{
l=gc(),r=gc();
l^=ans,r^=ans;
ans=query(l,r,1,n,root[r]);
printf("%lld\n",ans);
}
return 0;
}