BZOJ 4026 dC Loves Number Theory (主席树+数论+欧拉函数)

题目大意:给你一个序列,求出指定区间的\varphi (a[i])(l<=i<=r) mod 1000777 的值

还复习了欧拉函数以及线性筛逆元

考虑欧拉函数的的性质,\varphi (\prod a[i])(l<=i<=r),等价于\prod a[i]*\prod p[j]-1/p[j] (p[j]是区间内所有出现过的质数)

那么考虑找出区间内所有出现过的质数,这思路和HH的项链是不是很像??

由于此题强制在线,所以把树状数组替换成了主席树而已

原来我以前写的主席树一直都是错的......还好推出了我原来错误代码的反例

在继承上一个树的信息时,注意不要破坏现在的树

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #define ll long long 
  5 #define il inline
  6 #define N 50010
  7 #define maxn 1000000
  8 #define mod 1000777
  9 using namespace std;
 10  
 11 int n,q,ctp,tot;
 12 int root[N];
 13 int pr[maxn+100],use[maxn+100],lst[maxn+100];
 14 ll a[N],inv[mod+100],nxt[maxn+100];
 15 struct Seg{ll sum;int ls,rs;}seg[N*60]; //re
 16 void prime_inv()
 17 {
 18     for(int i=2;i<=maxn;i++)
 19     {
 20         if(!use[i])
 21             pr[++ctp]=i,nxt[i]=i;
 22         for(int j=1;j<=ctp&&i*pr[j]<=maxn;j++){
 23             use[i*pr[j]]=1,nxt[i*pr[j]]=pr[j];
 24             if(i%pr[j]==0) break;
 25         }
 26     }
 27     inv[0]=inv[1]=1;
 28     for(ll i=2;i<mod;i++)
 29         inv[i]=(mod-mod/i)*inv[mod%i]%mod;
 30 }
 31 ll gc()
 32 {
 33     ll ret=0,fh=1;char p=getchar();
 34     while(p<'0'||p>'9') {if(p=='-')fh=-1;p=getchar();}
 35     while(p>='0'&&p<='9') {ret=(ret<<3)+(ret<<1)+p-'0';p=getchar();}
 36     return ret*fh;
 37 }
 38 il void pushup(int rt){seg[rt].sum=(seg[seg[rt].ls].sum*seg[seg[rt].rs].sum)%mod;}
 39 void build(int l,int r,int rt)
 40 {
 41     seg[rt].sum=1;
 42     if(l==r)return;
 43     int mid=(l+r)>>1;
 44     seg[rt].ls=++tot,build(l,mid,tot);
 45     seg[rt].rs=++tot,build(mid+1,r,tot);
 46 }
 47 void update(int x,int l,int r,int rt1,int rt2,ll w)
 48 {
 49     if(l==r) {seg[rt2].sum=(seg[rt2].sum*w)%mod;return;}
 50     int mid=(l+r)>>1;
 51     if(x<=mid)
 52     {
 53         if(!seg[rt2].ls||seg[rt1].ls==seg[rt2].ls){
 54             seg[rt2].ls=++tot,seg[seg[rt2].ls].sum=seg[seg[rt1].ls].sum;
 55         if(!seg[rt2].rs) 
 56             seg[rt2].rs=seg[rt1].rs;
 57         } 
 58         update(x,l,mid,seg[rt1].ls,seg[rt2].ls,w);
 59     }else{
 60         if(!seg[rt2].rs||seg[rt1].rs==seg[rt2].rs){
 61             seg[rt2].rs=++tot,seg[seg[rt2].rs].sum=seg[seg[rt1].rs].sum;
 62         if(!seg[rt2].ls)
 63             seg[rt2].ls=seg[rt1].ls;
 64         }
 65         update(x,mid+1,r,seg[rt1].rs,seg[rt2].rs,w);
 66     }
 67     pushup(rt2);
 68 }
 69 ll query(int L,int R,int l,int r,int rt)
 70 {
 71     if(L<=l&&r<=R) return seg[rt].sum;
 72     int mid=(l+r)>>1;ll ans=1;
 73     if(L<=mid) ans*=query(L,R,l,mid,seg[rt].ls),ans%=mod;
 74     if(R>mid) ans*=query(L,R,mid+1,r,seg[rt].rs),ans%=mod;
 75     return ans;
 76 }
 77  
 78 int main()
 79 {
 80     //freopen("a.in","r",stdin);
 81     //freopen("a.out","w",stdout);
 82     scanf("%d%d",&n,&q);
 83     for(int i=1;i<=n;i++) a[i]=gc();
 84     prime_inv();
 85     root[0]=++tot;
 86     build(1,n,1);
 87     ll x,p,w;
 88     for(int i=1;i<=n;i++)
 89     {
 90         x=a[i],w=a[i],root[i]=++tot;
 91         while(x!=1){
 92             p=nxt[x];
 93             if(lst[p])
 94                 update(lst[p],1,n,root[i-1],root[i],(inv[p-1]*p)%mod);
 95             lst[p]=i;
 96             x/=p,w=((w*(p-(ll)1)%mod)*inv[p])%mod;
 97             while(x%p==0) x/=p;
 98         }
 99         update(i,1,n,root[i-1],root[i],w);
100     }
101     ll l,r,ans=0;
102     for(int i=1;i<=q;i++)
103     {
104         l=gc(),r=gc();
105         l^=ans,r^=ans;
106         ans=query(l,r,1,n,root[r]);
107         printf("%lld\n",ans);
108     }
109     return 0;
110 }

 

posted @ 2018-09-24 22:26  guapisolo  阅读(225)  评论(0编辑  收藏  举报