[BZOJ4105][Thu Summer Camp 2015]平方运算

题意

给定一个数列,有两种操作,询问一段区间 [l,r] 内的和或者对于 i[l,r] xi=xi 2%p


类似于[bzoj3038]上帝造题的七分钟的思想

因为存在取模,所以 xi 变成 xi 2%p 一定会存在循环,又因为p给的比较特殊,循环的大小也比较小,所以可以对于处在循环中的数打标记,不处在循环中的数暴力。

#include <cstdio>
#define N 100010

int n,m,p,A[N],app[N],op,l,r,ic[N],ced[N];

struct bt{
    int l,r,x[100],sz,bg,bic,sum,w;
}T[N<<2];

inline void reaD(int &x){
    char Ch=getchar();x=0;
    for(;Ch>'9'||Ch<'0';Ch=getchar());
    for(;Ch>='0'&&Ch<='9';x=x*10+Ch-'0',Ch=getchar());
}

inline void upd(int g){
    T[g].sum=T[g<<1].sum+T[g<<1|1].sum;
    if(!T[g<<1].bic||!T[g<<1|1].bic)return;
    int i=T[g<<1].bg,j=T[g<<1|1].bg;T[g].bic=1;
    T[g].bg=1;T[g].sz=0;
    do{
        T[g].x[++T[g].sz]=T[g<<1].x[i]+T[g<<1|1].x[j];
        if((++i)>T[g<<1].sz)i=1;
        if((++j)>T[g<<1|1].sz)j=1;
    }while(i!=T[g<<1].bg||j!=T[g<<1|1].bg);
}

void buc(int g,int l){
    T[g].bic=1;
    app[T[g].x[T[g].sz=1]=A[l]]=l;T[g].bg=1;
    while(l!=app[(T[g].x[T[g].sz]*T[g].x[T[g].sz])%p]){
        app[(T[g].x[T[g].sz]*T[g].x[T[g].sz])%p]=l;
        T[g].x[++T[g].sz]=(T[g].x[T[g].sz-1]*T[g].x[T[g].sz-1])%p;
    }
    T[g].sum=T[g].x[T[g].bg];
}

void build(int g,int l,int r){
    T[g].l=l;T[g].r=r;
    if(l==r){
        T[g].sum=A[l];
        if(!ic[A[l]]) return;
        buc(g,l);
        return ;
    }
    int mid=l+r>>1;
    build(g<<1,l,mid);build(g<<1|1,mid+1,r);
    upd(g);
}

inline void down(int g){
    if(T[g].w){
        T[g<<1].sum=T[g<<1].x[++((T[g<<1].bg+=T[g].w-1)%=T[g<<1].sz)];
        T[g<<1|1].sum=T[g<<1|1].x[++((T[g<<1|1].bg+=T[g].w-1)%=T[g<<1|1].sz)];
        T[g<<1].w+=T[g].w;T[g<<1|1].w+=T[g].w;
        T[g].w=0;
    }
}

void update(int g,int l,int r){
    if(T[g].l==l&&T[g].r==r){
        if(T[g].bic){if((++T[g].bg)>T[g].sz)T[g].bg=1;T[g].sum=T[g].x[T[g].bg];T[g].w++;return;}
        if(l==r){
            if(ic[(A[l]*=A[l])%=p])buc(g,l);
            T[g].sum=A[l];
            return;
        }
        down(g);
        int mid=T[g].l+T[g].r>>1;
        update(g<<1,T[g].l,mid);
        update(g<<1|1,mid+1,T[g].r);
        upd(g);
        return;
    }
    down(g);
    int mid=T[g].l+T[g].r>>1;
    if(r<=mid) update(g<<1,l,r); else
    if(l>mid) update(g<<1|1,l,r); else
    update(g<<1,l,mid),update(g<<1|1,mid+1,r);
    upd(g);
}

int query(int g,int l,int r){
    if(T[g].l==l&&T[g].r==r)return T[g].sum;
    down(g);
    int mid=T[g].l+T[g].r>>1;
    if(r<=mid) return query(g<<1,l,r);
    if(l>mid) return query(g<<1|1,l,r);
    return query(g<<1,l,mid)+query(g<<1|1,mid+1,r);
}

void dfs(int x){
    if(ic[x]) return;
    int k=x;
    ced[x]=k;x=x*x%p;
    while(ced[x]!=k){
        ced[x]=k;
        x=x*x%p;
    }
    int y=x;ic[x]=1;x=x*x%p;
    while(x!=y){
        ic[x]=1;
        x=x*x%p;
    }
}

int w[20],wt;

inline void Pt(int x){
    if(!x){putchar(48);putchar('\n');return;}
    while(x)w[++wt]=x%10,x/=10;
    for(;wt;wt--)putchar(w[wt]+48);putchar('\n');
}

int main(){
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
    reaD(n);reaD(m);reaD(p);
    for(int i=0;i<p;i++) dfs(i);
    for(int i=1;i<=n;i++) reaD(A[i]);
    build(1,1,n);
    for(int i=1;i<=m;i++){
        reaD(op);reaD(l);reaD(r);
        if(op==0) update(1,l,r);
        else Pt(query(1,l,r));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值