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的项链是不是很像??

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

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

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

#include 
#include 
#include 
#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'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;
}

 

你可能感兴趣的:(bzoj,主席树,数论,欧拉函数)