BZOJ 4026 dC Loves Number Theory 分块+十字链表/可持久化线段树

题目大意:给定一个序列,多次询问某段区间乘积的 φ 值对 1000777 的模

我竟然卡过去了233333
将序列分块,记录 fi,j 表示第 i 块左端点到第 j 个点中出现的所有质数 p p1p 之积
每次询问 [x,y] ,首先取出 [x,y] 区间内所有数的积,然后乘上 fst,y (其中 st x 后面第一个块端点所在块)
现在还剩 [x,l[st]] 部分没有统计
由于 106 以内的数分解得到的不同的质因数最多只有 7 个,因此暴力枚举零碎部分的质数即可
现在对于每个质数我们需要判断是否出现过
我们只需要判断这个质数下一次出现的位置是否大于 y 即可
用十字链表搞一搞就可以了
时间复杂度 O(7mn)

这当然不是正解- -
珍爱生命,远离卡常,我们来看正解吧

实际上我们要统计的就是 [x,y] 区间内所有出现过的质数 p p1p 之积
我们想到了什么?没错,HH的项链!
由于强制在线,因此我们用可持久化线段树搞一搞就行了。时间复杂度 O(mlogn)

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 50500
#define B 700
#define MOD 1000777
using namespace std;
struct abcd{
    abcd *up,*rt;
    int p,belong;
    void* operator new (size_t)
    {
        static abcd mempool[M*7],*C=mempool;
        return C++;
    }
}*head[M],*last[80800];
int n,m,b,last_ans;
int a[M];
int prime[80800],tot;
long long inv[MOD];
int l[M],belong[M];
int prod[B][M];
void Linear_Shaker()
{
    static bool not_prime[1001001];
    int i,j;
    for(i=2;i<=1000000;i++)
    {
        if(!not_prime[i])
            prime[++tot]=i;
        for(j=1;prime[j]*i<=1000000;j++)
        {
            not_prime[prime[j]*i]=true;
            if(i%prime[j]==0)
                break;
        }
    }
    for(inv[1]=1,i=2;i<MOD;i++)
        inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD;
}
abcd* Decomposition(int pos)
{
    int i,n=a[pos];
    abcd *re=0x0;
    for(i=1;prime[i]*prime[i]<=n;i++)
        if(n%prime[i]==0)
        {
            abcd *temp=new abcd;
            temp->up=re;
            temp->p=i;
            temp->belong=pos;
            if(last[i])
                last[i]->rt=temp;
            re=last[i]=temp;

            while(n%prime[i]==0)
                n/=prime[i];
        }
    if(n!=1)
    {
        i=lower_bound(prime+1,prime+tot+1,n)-prime;

        abcd *temp=new abcd;
        temp->up=re;
        temp->p=i;
        temp->belong=pos;
        if(last[i])
            last[i]->rt=temp;
        re=last[i]=temp;
    }
    return re;
}
int Query(int x,int y)
{
    int i,st=belong[x-1]+1,re=inv[a[x-1]]*a[y]%MOD;
    abcd *temp;
    if(y>=l[st])
        re=(long long)re*prod[st][y]%MOD;
    for(i=min(y,l[st]-1);i>=x;i--)
        for(temp=head[i];temp;temp=temp->up)
            if(!temp->rt||temp->rt->belong>y)
                re=re*inv[prime[temp->p]]%MOD*(prime[temp->p]-1)%MOD;
    return re;
}
namespace IStream{  
    const int L=1<<15;  
    char buffer[L],*S,*T;  
    inline char Get_Char()  
    {  
        if(S==T)  
        {  
            T=(S=buffer)+fread(buffer,1,L,stdin);  
            if(S==T) return EOF;  
        }  
        return *S++;  
    }  
    inline int Get_Int()  
    {  
        char c;  
        int re=0;  
        for(c=Get_Char();c<'0'||c>'9';c=Get_Char());  
        while(c>='0'&&c<='9')  
            re=(re<<1)+(re<<3)+(c-'0'),c=Get_Char();  
        return re;  
    }  
}
int main()
{
    using namespace IStream;
    int i,j,x,y;
    abcd *temp;
    cin>>n>>m;
    b=200;
    Linear_Shaker();
    for(i=1;i<=n;i++)
    {
        a[i]=Get_Int();
        head[i]=Decomposition(i);
    }
    for(a[0]=1,i=1;i<=n;i++)
        a[i]=(long long)a[i]*a[i-1]%MOD;
    for(i=1;i<=n;i++)
        belong[i]=(i-1)/b+1;
    for(i=1;i<=belong[n];i++)
        l[i]=(i-1)*b+1;
    l[i]=0x3f3f3f3f;

    static int v[80800],ans;
    for(j=1;j<=belong[n];j++)
    {
        ans=1;
        for(i=l[j];i<=n;i++)
        {
            for(temp=head[i];temp;temp=temp->up)
                if(v[temp->p]!=j)
                {
                    v[temp->p]=j;
                    ans = ans * inv[prime[temp->p]] % MOD * (prime[temp->p]-1) % MOD ;
                }
            prod[j][i]=ans;
        }
    }

    for(i=1;i<=m;i++)
    {
        x=Get_Int();
        y=Get_Int();
        x^=last_ans;
        y^=last_ans;
        printf("%d\n",last_ans=Query(x,y));
    }
    //puts("Fuck♂You!");
    return 0;
}

你可能感兴趣的:(分块,bzoj,可持久化线段树,可持久化数据结构,BZOJ4026)