• 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
    ";
    #else
        const char LL[]="%lld
    ";
    #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
    ",query(1,l,r));
        }
        return 0;
    }
  • 相关阅读:
    Linux内存管理1---内存寻址
    UML和模式应用5:细化阶段(10)---UML交互图
    AT91RM9200---电源管理控制器(PMC)介绍
    AT91RM9200---定时器简介
    [转]指针大小是由谁决定的?
    UML和模式应用5:细化阶段(9)---迈向对象设计
    UML和模式应用5:细化阶段(8)---逻辑架构和UML包图
    UML和模式应用5:细化阶段(7)---从需求到设计迭代进化
    UML和模式应用5:细化阶段(6)---操作契约
    VxWorks软件开发项目实例完全解析1-VxWorks简介
  • 原文地址:https://www.cnblogs.com/Gloid/p/9923981.html
Copyright © 2020-2023  润新知