Codeforces Round #675 (Div. 2) F.Boring Queries(主席树+lcm)

    科技2022-09-05  129

    题目

    长度为n(n<=1e5)的数组a[],ai在[1,2e5]之间,

    q(q<=1e5)个询问,每次给出[l,r],询问[l,r]区间内的ai的lcm,

    本题强制在线

    思路来源

    ustze、Heltion代码

    题解

    强制在线,n=1e5,所以用主席树,

    主席树直接维护区间乘积,所以要将lcm引起的乘积变小的部分预先除掉,

    询问[l,r]的时候,直接回答r为右端点的主席树在[l,r]的区间乘积

     

    考虑lcm,对于每个质因子p来说,若区间内有两个含p的数,则

    lcm应该是几个有这个质因子的数的出现次数最大值,

    类似询问区间mex以及可持久化结构的一些套路,让每个值的出现位置尽可能靠右

    此处需要维护质因子使其尽可能靠右,具体来说

    此处为主席树root[3]的维护过程,

    对于每个p的幂次,都维护一个其出现的最右的位置,

    只让蓝色的区域在lcm中有贡献,此为代码1

     

    而代码2,则是维护了一个栈,栈中放入(质因子的位置,当前还剩的幂次)

    如果当前最右可以与左侧的比它小的幂次抵消,则尽可能抵消,

    然后将当前最右的幂次放入栈中

    代码1

    #include<bits/stdc++.h> using namespace std; const int N=2e5+10,mod=1e9+7; typedef pair<int,int> P; #define fi first #define se second int n,q,x,y,l,r,lasans; int a[N],inv[N]; //空间 log(2e5)质因子个数*log(1e5)一条链*n 18*17*1e5 int root[N],ls[200*N],rs[200*N],lcm[200*N],mxp[N],rig[N],c; vector<P>p[N],now[N]; int modpow(int x,int n,int mod){ int res=1; for(;n;n>>=1,x=1ll*x*x%mod){ if(n&1)res=1ll*res*x%mod; } return res; } void upd(int l,int r,int &cur,int las,int pos,int v){ cur=++c; ls[cur]=ls[las];rs[cur]=rs[las]; lcm[cur]=1ll*lcm[las]*v%mod; if(l==r){ return; } int mid=(l+r)/2; if(pos<=mid)upd(l,mid,ls[cur],ls[las],pos,v); else upd(mid+1,r,rs[cur],rs[las],pos,v); } int ask(int cur,int l,int r,int ql,int qr){ if(!cur){ return 1; } if(ql<=l && r<=qr){ return lcm[cur]; } int mid=(l+r)/2,res=1; if(ql<=mid)res=1ll*res*ask(ls[cur],l,mid,ql,qr)%mod; if(qr>mid)res=1ll*res*ask(rs[cur],mid+1,r,ql,qr)%mod; return res; } int main(){ inv[1]=1; lcm[0]=1; for(int i=2;i<N;++i){ inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod; if(!mxp[i]){ for(int j=i;j<N;j+=i){ mxp[j]=i; } } } scanf("%d",&n); for(int i=1;i<=n;++i){ scanf("%d",&a[i]); root[i]=root[i-1]; for(int v=a[i];v!=1;){ int x=v,pc=1; while(x%mxp[v]==0){ x/=mxp[v]; pc*=mxp[v]; if(rig[pc]){ upd(1,n,root[i],root[i],rig[pc],inv[mxp[v]]); } rig[pc]=i; } upd(1,n,root[i],root[i],rig[pc],pc); v=x; } } scanf("%d",&q); while(q--){ scanf("%d%d",&x,&y); l=(lasans+x)%n+1;r=(lasans+y)%n+1; if(l>r)swap(l,r); printf("%d\n",lasans=ask(root[r],1,n,l,r)); } return 0; }

    代码2

    #include<bits/stdc++.h> using namespace std; const int N=2e5+10,mod=1e9+7; typedef pair<int,int> P; #define fi first #define se second int n,q,x,y,l,r,lasans; int a[N],inv[N]; int root[N],ls[200*N],rs[200*N],lcm[200*N],c; vector<P>p[N],now[N]; int modpow(int x,int n,int mod){ int res=1; for(;n;n>>=1,x=1ll*x*x%mod){ if(n&1)res=1ll*res*x%mod; } return res; } void upd(int l,int r,int &cur,int las,int pos,int v){ cur=++c; ls[cur]=ls[las];rs[cur]=rs[las]; lcm[cur]=1ll*lcm[las]*v%mod; if(l==r){ return; } int mid=(l+r)/2; if(pos<=mid)upd(l,mid,ls[cur],ls[las],pos,v); else upd(mid+1,r,rs[cur],rs[las],pos,v); } int ask(int cur,int l,int r,int ql,int qr){ if(!cur){ return 1; } if(ql<=l && r<=qr){ return lcm[cur]; } int mid=(l+r)/2,res=1; if(ql<=mid)res=1ll*res*ask(ls[cur],l,mid,ql,qr)%mod; if(qr>mid)res=1ll*res*ask(rs[cur],mid+1,r,ql,qr)%mod; return res; } int main(){ inv[1]=1; lcm[0]=1; for(int i=2;i<N;++i){ inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod; if(p[i].empty()){ for(int j=i;j<N;j+=i){ int num=0; for(int k=j;k%i==0;k/=i){ num++; } p[j].push_back(P(i,num)); } } } scanf("%d",&n); for(int i=1;i<=n;++i){ scanf("%d",&a[i]); root[i]=root[i-1]; for(auto x:p[a[i]]){ int v=x.fi,cnt=x.se,lef=cnt; while(!now[v].empty() && lef){ int h=min(now[v].back().se,lef); lef-=h;now[v].back().se-=h; upd(1,n,root[i],root[i],now[v].back().fi,modpow(inv[v],h,mod)); if(now[v].back().se==0){ now[v].pop_back(); } } if(cnt){ upd(1,n,root[i],root[i],i,modpow(v,cnt,mod)); now[v].push_back(P(i,cnt)); } } } scanf("%d",&q); while(q--){ scanf("%d%d",&x,&y); l=(lasans+x)%n+1;r=(lasans+y)%n+1; if(l>r)swap(l,r); printf("%d\n",lasans=ask(root[r],1,n,l,r)); } return 0; }
    Processed: 0.008, SQL: 10