BZOJ 4026 dC Loves Number Theory 主席树


题目大意:中文题自己看


首先phi[i] = i * (1 - p1) ... * (1 - pn)


由于每一个质因数p只用了一次,所以对区间做HH 的项链就好了.


PS: 我真是太弱了,差点写吐了QAQ...


#include <stdio.h>
#include <cstring>
#include <iostream>
#include <algorithm>
typedef long long ll;
#define N 1000000UL
#define MAXN 50005UL
#define mod 1000777UL
int n,Q,prime[1000005],tot,last[1000005],val[MAXN];
bool _prime[1000005];
ll Ans,use[1000005],fac[MAXN];
    
    
template<typename _t>
inline _t read(){
    _t x=0,f=1;
    char ch=getchar();
    for(;ch>'9'||ch<'0';ch=getchar())if(ch=='-')f=-f;
    for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+(ch^48);
    return x*f;
}
    
inline ll qpow(ll x,ll k){
    ll Ans = 1;
    for(;k;k>>=1,x = 1ll * x * x % mod) if(k&1) Ans = Ans * x % mod;
    return Ans;
}
 
int first[1000005],e = 1;
 
struct edge{
    int u,v,next;
}a[3000005];
 
inline void push(int u,int v){
    a[e].u=u;a[e].v=v;a[e].next=first[u];first[u]=e++;
}
    
inline void init(){
    for(int i = 2;i<=N;i++) {
        if(!_prime[i]) {
            prime[++tot] = i;
            for(int j = i;j<=N;j+=i){
                _prime[j] = 1;
                push(j,tot);
            }
        }
    }
    for(int i = 1;i<=tot;i++) use[i] = 1ll * (prime[i]-1) * qpow(prime[i],mod-2) % mod;
}
    
namespace CMT{
    int root[MAXN],cnt;
    struct node{
        int l,r; ll sum;
    }tree[MAXN*100];
    
    inline void build(int &o,int l,int r){
        o = ++ cnt; tree[o].sum = 1;
        if(l == r) return;
        register int mid = l + r >> 1;
        build(tree[o].l,l,mid);build(tree[o].r,mid+1,r);
    }
    
    inline void Update(int &o,int old,int l,int r,int x,ll val){
        o = ++ cnt; tree[o] = tree[old];
        tree[o].sum = tree[old].sum * val % mod;
        if(l == r) return;
        register int mid = l + r >> 1;
        if(x<=mid) Update(tree[o].l,tree[old].l,l,mid,x,val);
        else Update(tree[o].r,tree[old].r,mid+1,r,x,val);
    }
    
    inline ll Query(int o,int l,int r,int x,int y){
        if(x<=l&&r<=y) return tree[o].sum;
        register int mid = l + r >> 1; ll Ans = 1;
        if(x<=mid) Ans = Ans * Query(tree[o].l,l,mid,x,y) % mod;
        if(mid<y) Ans = Ans * Query(tree[o].r,mid+1,r,x,y) % mod;
        return Ans;
    }
}
    
using namespace CMT;
    
inline void work(int x,int id){
    int num = root[id - 1];
    ll sum = 1;
    for(int i = first[x];i;i=a[i].next) {
        if(x%prime[a[i].v] == 0){
            while(x % prime[a[i].v] == 0) x /= prime[a[i].v];
            if(last[prime[a[i].v]]) Update(num,num,1,n,last[prime[a[i].v]],qpow(use[a[i].v],mod-2));
            last[prime[a[i].v]] = id;
            sum = sum * use[a[i].v] % mod;
        }
    }
    Update(root[id],num,1,n,id,sum);
}
    
inline void Query(){
    register int l = read<int>() ^ Ans , r = read<int>() ^ Ans;
    Ans = Query(root[r],1,n,l,r);
    Ans = Ans * fac[r] % mod * qpow(fac[l-1],mod-2) % mod;
    printf("%lld\n",Ans);
}
    
int main(){
    init();
    n = read<int>();Q = read<int>(); fac[0] = 1;build(root[0],1,n); 
    for(int i = 1;i<=n;i++) val[i] = read<int>(),fac[i] = fac[i-1] * val[i] % mod;
    for(int i = 1;i<=n;i++) work(val[i],i);
    while(Q --) Query();
    return 0;
}







posted @ 2017-09-24 07:50  cooook  阅读(140)  评论(0编辑  收藏  举报