bzoj 4026 dC Loves Number Theory 主席树+欧拉函数
题目描述
输入格式
输出格式
样例
数据范围与提示
这是个比较高级的的题目。。。原来一直是开权值的主席树,看到此题首先想到莫比乌斯反演,但是本题用最简单的容斥算欧拉即可。也就是说每个点都有相应的质因数,这些质因数不重复的相乘即为最难维护的部分,考虑主席树要存 在加入该点后每个线段树区间的phi值情况,最后用区间拼凑,要每个点都考虑是因为加入该点后之前区间的质数不再对答案做贡献,我们只算最新加入的相同质数,如果要是想只算第一次加入的话,后面的区间就没法计算贡献,而主席树可以访问历史状态,因此我们可以访问加入该节点之前的状态,所以存最新的相同质数可以达到我们的目的,那么具体操作就是,就是我们扫描整个数组,然后对它分解质因数,用一个pre数组记录某个质数最早出现的位置,如果为零,直接把这个质数的贡献((pi-1)/pi)乘入该点主席树的位置,如果不为零,考虑在现在版本上去掉该质数之前区间的贡献,即在现在点的主席树pre位置除以(pi-1)/pi,当然在此题有取模,所以我们可以用逆元,(不要怂,其实逆元代码也就一行)这题细节贼多,日了我好久。。。。注意数组多开点,因为这个主席树你改一次加条链,一个大数质因数可能特别多,然后就成RE树了。
Code:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const int M=50020,mod=1e6+777; int rt[M*80],lc[M*80],rc[M*80],z[2*mod+20],tt,n,m,tot; int fac[2*mod+20],pre[2*mod+20],a[M*40],p[2*mod+20],inv[2*mod+20]; int sum[M*80]; int rd() { char cc=getchar(); int s=0,w=1; while(cc<'0'||cc>'9'){if(cc=='-')w=-1;cc=getchar();} while(cc>='0'&&cc<='9') s=(s<<3)+(s<<1)+cc-'0',cc=getchar(); return s*w; } void first() { for(int i=2;i<=mod;i++) { if(p[i]==0){p[i]=i;z[++tot]=i;} for(int j=1;j<=tot;j++) { if(z[j]>p[i]||z[j]>(mod/i)) break; p[i*z[j]]=z[j]; } } inv[1]=1; for(int i=2;i<mod;i++) inv[i]=(1ll*(mod-mod/i)*inv[mod%i])%mod; } void build(int &k,int l,int r) { k=++tt; sum[k]=1; if(l==r) return; int mid=(l+r)>>1; build(lc[k],l,mid);build(rc[k],mid+1,r); } void modify(int &x,int k,int l,int r,int ip,ll w) { x=++tt; lc[x]=lc[k];rc[x]=rc[k]; sum[x]=(1ll*sum[k]*w)%mod; if(l==r) return; int mid=(l+r)>>1; if(ip<=mid) modify(lc[x],lc[k],l,mid,ip,w); else modify(rc[x],rc[k],mid+1,r,ip,w); } int query(int k,int l,int r,int x,int y) { int mid=(l+r)>>1; if(l==x&&r==y) return sum[k]; if(y<=mid) return query(lc[k],l,mid,x,y); else if(x>mid) return query(rc[k],mid+1,r,x,y); return 1ll*query(lc[k],l,mid,x,mid)*query(rc[k],mid+1,r,mid+1,y)%mod; } void cut(int k) { int nn=a[k],wi=a[k],tmp1=1,tmp2=1; while(nn!=1) { int y=p[nn]; while(nn%y==0) nn/=y; if(pre[y]) { if(rt[k]==0) modify(rt[k],rt[k-1],1,n,pre[y],(1ll*inv[y-1]*y)%mod); else modify(rt[k],rt[k],1,n,pre[y],(1ll*inv[y-1]*y)%mod); } wi=((1ll*wi*(y-1)%mod)*inv[y])%mod; pre[y]=k; } if(rt[k]==0) modify(rt[k],rt[k-1],1,n,k,(1ll*wi)%mod); else modify(rt[k],rt[k],1,n,k,(1ll*wi)%mod); } int main() { first(); n=rd(),m=rd(); fac[0]=1; build(rt[0],1,n); for(int i=1;i<=n;i++) { a[i]=rd(); cut(i); } int last=0; for(int i=1;i<=m;i++) { int l=rd()^last,r=rd()^last; last=(1ll*query(rt[r],1,n,l,r)%mod); printf("%d\n",last); } }
Zeit und Raum trennen dich und mich.时空将你我分开。