bzoj 4026: dC Loves Number Theory 可持久化线段树

来源:互联网 发布:怎样查nginx的版本 编辑:程序博客网 时间:2024/06/07 05:36

题意

给出一个长度为n的序列A,有q个询问,每次询问φ()。强制在线。
n<=50000,q<=100000,Ai<=1000000

分析

又学到了新姿势。

首先考虑如何强制在线求一个区间内不同数的个数。
我们对序列建可持久化线段树,线段树下标表示位置而不是权值。对于位置i上的数x,我们把i的可持久化线段树上的位置i加上1。对于上一个出现了x的位置j,我们把i的可持久化线段树上的位置j减去1。假设要查询区间[l,r],那么就直接查询r的可持久化线段树上的区间[l,r]即可。正确性的话只要随便yy一下就比较显然了。

现在考虑这一题怎么做。
显然我们要求的是pi1pi其中pi为素数。那么对于一个位置i上的数,我们将其分解质因数,对于一个素因子p,将位置i乘上p1p,将上一个出现了素因子p的位置j乘上pp1即可。

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>using namespace std;typedef long long LL;const int N=50005;const int M=1000005;const int MOD=1000777;int n,q,prime[M],tot,ny[M],ny1[M],low[M],a[N],sz,root[N],ls[M];bool not_prime[M];struct tree{int l,r,mul,s;}t[N*200];int read(){    int x=0,f=1;char ch=getchar();    while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}int ksm(int x,int y){    int ans=1;    while (y)    {        if (y&1) ans=(LL)ans*x%MOD;        x=(LL)x*x%MOD;y>>=1;    }    return ans;}void get_prime(int n){    for (int i=2;i<=n;i++)    {        if (!not_prime[i]) prime[++tot]=i,low[i]=tot;        for (int j=1;j<=tot&&i*prime[j]<=n;j++)        {            not_prime[i*prime[j]]=1;            low[i*prime[j]]=j;            if (i%prime[j]==0) break;        }    }}void build(int &d,int l,int r){    d=++sz;    if (l==r)    {        t[d].mul=a[l];t[d].s=1;        return;    }    int mid=(l+r)/2;    build(t[d].l,l,mid);build(t[d].r,mid+1,r);    t[d].mul=(LL)t[t[d].l].mul*t[t[d].r].mul%MOD;    t[d].s=(LL)t[t[d].l].s*t[t[d].r].s%MOD;}void ins(int &d,int p,int l,int r,int x,int y){    d=++sz;t[d]=t[p];t[d].s=(LL)t[d].s*y%MOD;    if (l==r) return;    int mid=(l+r)/2;    if (x<=mid) ins(t[d].l,t[p].l,l,mid,x,y);    else ins(t[d].r,t[p].r,mid+1,r,x,y);}int query(int d,int l,int r,int x,int y){    if (x>y) return 1;    if (l==x&&r==y) return (LL)t[d].mul*t[d].s%MOD;    int mid=(l+r)/2;    return (LL)query(t[d].l,l,mid,x,min(y,mid))*query(t[d].r,mid+1,r,max(x,mid+1),y)%MOD;}int main(){    get_prime(1000000);    for (int i=1;i<=tot;i++) ny[i]=ksm(prime[i],MOD-2),ny1[i]=ksm(prime[i]-1,MOD-2);    n=read();q=read();    for (int i=1;i<=n;i++) a[i]=read();    build(root[0],1,n);    for (int i=1;i<=n;i++)    {        int tmp=a[i];root[i]=root[i-1];        while (tmp>1)        {            int w=low[tmp];            while (tmp%prime[w]==0) tmp/=prime[w];            if (ls[w]) ins(root[i],root[i],1,n,ls[w],(LL)prime[w]*ny1[w]%MOD);            ins(root[i],root[i],1,n,i,(LL)(prime[w]-1)*ny[w]%MOD);            ls[w]=i;        }    }    int ans=0;    while (q--)    {        int l=read()^ans,r=read()^ans;        printf("%d\n",ans=query(root[r],1,n,l,r));    }    return 0;}
原创粉丝点击