Ynoi2016 炸脖龙I

Link
首先考虑没有修改的情况。显然直接暴力Ex-Euler定理就行了,单次复杂度为\(O(\log p)\)的。
现在有了修改,我们可以树状数组维护差分数组,然后\(O(\log n)\)地单次查询单点值。

#include<bits/stdc++.h>
#define LL long long
using namespace std;
namespace IO
{
    char ibuf[(1<<21)+1],obuf[(1<<21)+1],st[15],*iS,*iT,*oS=obuf,*oT=obuf+(1<<21);
    char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
    void Flush(){fwrite(obuf,1,oS-obuf,stdout),oS=obuf;}
    void Put(char x){*oS++=x;if(oS==oT)Flush();}
    int read(){int x=0;char ch=Get();while(ch>57||ch<48)ch=Get();while(ch>=48&&ch<=57)x=x*10+(ch^48),ch=Get();return x;}
    void write(int x){int top=0;if(x<0)Put('-'),x=-x;if(!x)Put('0');while(x)st[++top]=(x%10)+48,x/=10;while(top)Put(st[top--]);Put('\n');}
}
using namespace IO;
void max(int &a,int b){a=a>b? a:b;}
#define N 500007
#define M 20000007
int n,phi[M],p[M>>3],opt[N],l[N],r[N],P[N];
bitset<M>vis;
LL c[N];
void add(int p,int v){while(p<=n)c[p]+=v,p+=p&-p;}
LL query(int p){LL v=0;while(p)v+=c[p],p-=p&-p;return v;}
void modify(int l,int r,int v){add(l,v),add(r+1,-v);}
struct node{LL num;int flg;node(LL Num=0,int Flg=0):num(Num),flg(Flg){}};
node power(LL a,int k,int p)
{
    node ans=node(1,0);
    if(a>=p) a%=p,ans.flg=1;
    while(k)
    {
	if(k&1) ans.num=ans.num*a;
	if(ans.num>=p) ans.num%=p,ans.flg=1;
	a*=a,k>>=1;
	if(a>=p) a%=p,ans.flg=1;
    }
    return ans;
}
node calc(int l,int r,int p)
{
    LL a=query(l);
    if(p==1) return node(0,1);
    if(a==1) return node(1,0);
    if(l==r) return a<p? node(a,0):node(a%p,1);
    int Phi=phi[p];node ans=calc(l+1,r,Phi);
    if(ans.flg) ans.num+=Phi;
    return power(a,ans.num,p);
}
int main()
{
    n=read();int Q=read(),i,j,tot=0,Max=0;
    for(i=1;i<=n;++i) tot=read(),modify(i,i,tot);
    for(i=1;i<=Q;++i)
    {
	opt[i]=read(),l[i]=read(),r[i]=read(),P[i]=read();
	if(opt[i]==2) max(Max,P[i]);
    }
    for(tot=0,phi[1]=1,i=2;i<=Max;++i)
    {
	if(!vis[i]) p[++tot]=i,phi[i]=i-1;
	for(j=1;i*p[j]<=Max&&j<=tot;++j)
	{
	    vis[i*p[j]]=1;
	    if(!(i%p[j])){phi[i*p[j]]=phi[i]*p[j];break;}
	    phi[i*p[j]]=phi[i]*(p[j]-1);
	}
    }    
    for(i=1;i<=Q;++i)if(opt[i]==1) modify(l[i],r[i],P[i]); else write(calc(l[i],r[i],P[i]).num);
    return Flush(),0;
}
posted @ 2019-11-22 19:19  Shiina_Mashiro  阅读(206)  评论(0编辑  收藏  举报