BZOJ4105 THUSC2015平方运算(线段树)

  注意到模数被给出且非常小,做法肯定要依赖于一些与此相关的性质。找题解打表可以发现循环节长度的lcm不超过60。

  考虑怎么用线段树维护循环。对线段树上每个点维护这段区间的循环节、在循环中的位置,如果未进入环特殊记录;每次修改对于未进入环的暴力修改,已进入环的更新在循环节上的位置即可。对于修改经过的节点暴力重构循环节。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 100010
char getc(){char c=getchar();while (c==10||c==13||c==32) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
int n,m,p,a[N];
int L[N<<2],R[N<<2],value[N<<2][61],len[N<<2],pos[N<<2],sum[N<<2],lazy[N<<2];
bool flag[N];
void up(int k)
{
    int x=pos[k<<1],y=pos[k<<1|1];
    for (int i=0;i<len[k];i++)
    {
        value[k][i]=value[k<<1][x]+value[k<<1|1][y];
        x=(x+1)%len[k<<1],y=(y+1)%len[k<<1|1];
    }
    pos[k]=0;
}
void build(int k,int l,int r)
{
    L[k]=l,R[k]=r;
    if (l==r)
    {
        sum[k]=a[l];
        int x=a[l];
        while (!flag[x]) flag[x]=1,x=x*x%p;
        int y=a[l];
        while (y!=x) pos[k]--,flag[y]=0,y=y*y%p;
        do
        {
            value[k][len[k]++]=y;
            flag[y]=0;
            y=y*y%p;
        }while (y!=x);
        return;
    }
    int mid=l+r>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    len[k]=len[k<<1]*len[k<<1|1]/gcd(len[k<<1],len[k<<1|1]);
    pos[k]=min(pos[k<<1],pos[k<<1|1]);
    sum[k]=sum[k<<1]+sum[k<<1|1];
    if (pos[k]==0) up(k);
}
void update(int k,int x){sum[k]=value[k][pos[k]=(pos[k]+x)%len[k]],lazy[k]+=x;}
void down(int k){update(k<<1,lazy[k]),update(k<<1|1,lazy[k]),lazy[k]=0;}
void modify(int k,int l,int r)
{
    if (L[k]==l&&R[k]==r)
    {
        if (pos[k]>=0) update(k,1);
        else if (L[k]==R[k]) sum[k]=sum[k]*sum[k]%p,pos[k]++;
        else
        {
            pos[k]++;
            if (lazy[k]) down(k);
            modify(k<<1,l,L[k]+R[k]>>1);
            modify(k<<1|1,(L[k]+R[k]>>1)+1,r);
            sum[k]=sum[k<<1]+sum[k<<1|1];
            if (pos[k]==0) up(k);
        }
        return;
    }
    if (lazy[k]) down(k);
    int mid=L[k]+R[k]>>1;
    if (r<=mid) modify(k<<1,l,r);
    else if (l>mid) modify(k<<1|1,l,r);
    else modify(k<<1,l,mid),modify(k<<1|1,mid+1,r);
    sum[k]=sum[k<<1]+sum[k<<1|1];
    if (pos[k]>=0) up(k);
}
int query(int k,int l,int r)
{
    if (L[k]==l&&R[k]==r) return sum[k];
    if (lazy[k]) down(k);
    int mid=L[k]+R[k]>>1;
    if (r<=mid) return query(k<<1,l,r);
    else if (l>mid) return query(k<<1|1,l,r);
    else return query(k<<1,l,mid)+query(k<<1|1,mid+1,r);
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj4105.in","r",stdin);
    freopen("bzoj4105.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    n=read(),m=read(),p=read();
    for (int i=1;i<=n;i++) a[i]=read();
    build(1,1,n);
    while (m--)
    {
        int op=read(),l=read(),r=read();
        if (op==0) modify(1,l,r);
        else printf("%d\n",query(1,l,r));
    }
    return 0;
}

 

posted @ 2018-11-08 01:48  Gloid  阅读(383)  评论(0编辑  收藏  举报