bzoj千题计划271:bzoj4869: [六省联考2017]相逢是问候

http://www.lydsy.com/JudgeOnline/problem.php?id=4869

欧拉降幂+线段树,每个数最多降log次,模数就会降为1

#include<cmath>
#include<cstdio>
#include<iostream>

using namespace std;

#define N 50001

int n,m,p,c;
int a[N];

int sum[N<<2];
int tag[N<<2];

int lim,pi[101],phi[101];

int ans;

bool flag;

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}

int Pow(int a,int b,int mod)
{
    int res=1;
    while(b)
    {
        if(b&1)
        {
            if(1LL*res*a>=mod) flag=true;
            res=1LL*res*a%mod;    
        }
        if(1LL*a*a>=mod) flag=true;
        a=1LL*a*a%mod;
        b>>=1;
    }
    return res;
}

void build(int k,int l,int r)
{
    if(l==r)
    {
        sum[k]=a[l];
        return;
    }
    int mid=l+r>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    sum[k]=(sum[k<<1]+sum[k<<1|1])%p;
}

int get_phi(int x)
{
    int y=sqrt(x);
    int ph=x;
    for(int i=2;i<=y;++i)
        if(!(x%i))
        {
            while(!(x%i)) x/=i;
            ph=ph/i*(i-1);
        }
    if(x>1) ph=ph/x*(x-1);
    return ph;
}

int f(int dep,int x)
{
    int tmp=x;
    if(tmp>=phi[dep]) tmp=tmp%phi[dep]+phi[dep];
    for(int i=dep;i;--i)
    {
        flag=false;
        tmp=Pow(c,tmp,pi[i]);
        if(flag) tmp+=phi[i-1];
    }
    return tmp;
}

void change(int k,int l,int r,int opl,int opr)
{
    if(tag[k]>=lim) return;
    if(l==r)
    {
        tag[k]++;
        sum[k]=f(tag[k],a[l]);
        return;
    }
    int mid=l+r>>1;
    if(opl<=mid) change(k<<1,l,mid,opl,opr);
    if(opr>mid) change(k<<1|1,mid+1,r,opl,opr);
    tag[k]=min(tag[k<<1],tag[k<<1|1]);
    sum[k]=(sum[k<<1]+sum[k<<1|1])%p;
}

void query(int k,int l,int r,int opl,int opr)
{
    if(l>=opl && r<=opr)
    {
        ans+=sum[k];
        ans%=p;
        return;
    }
    int mid=l+r>>1;
    if(opl<=mid) query(k<<1,l,mid,opl,opr);
    if(opr>mid) query(k<<1|1,mid+1,r,opl,opr);
}

int main()
{
    read(n); read(m); read(p); read(c);
    for(int i=1;i<=n;++i) read(a[i]);
    build(1,1,n);
    int tmp=p;
    while(pi[lim]!=1)
    {
        pi[++lim]=tmp;
        phi[lim]=get_phi(tmp);
        tmp=phi[lim];
    }
    int ty,l,r;
    while(m--)
    {
        read(ty); read(l); read(r);
        if(!ty) change(1,1,n,l,r);
        else 
        {
            ans=0;
            query(1,1,n,l,r);
            printf("%d
",ans);
        }
    }
    return 0;
}
迭代降幂
原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8543188.html