bzoj4105: [Thu Summer Camp 2015]平方运算

填坑

我不知道怎么算的,但是所有环的LCM数不会超过60

然后用线段树维护这个东西,每个节点记录子树内的循环节

没到循环节的暴力枚举

复杂度是nlogn再乘以循环节长度

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<vector>

#define lc (now<<1)
#define rc (now<<1|1)
#define mid (ql+qr)/2
using namespace std;
typedef long long LL;
const int _=1e2;
const int maxn=1e5+_;
const int maxp=1e4+_;
const int maxh=62+10;
const int mbit=(1<<17)+_;
int gcd(int a,int b){if(a==0)return b;return gcd(b%a,a);}
int lcm(int a,int b){return a/gcd(a,b)*b;}

int nxt[maxp];bool inh[maxp];int tim,v[maxp];
void init(int p)
{
    for(int i=0;i<p;i++)nxt[i]=i*i%p;
    tim=0;
    for(int i=0;i<p;i++)
        if(v[i]==0)
        {
            v[i]=++tim;
            for(int k=nxt[i];;k=nxt[k])
            {
                if(v[k]==tim)
                {
                    inh[k]=true;
                    for(int u=nxt[k];u!=k;u=nxt[u])inh[u]=true;
                    break;
                }
                if(v[k]>0)break;
                v[k]=tim;
            }
        }
}

//--------------------------------------yu---------------------------------------------------

struct hh
{
    int len,pos,h[maxh];
    hh(){}
    int insert(int d)
    {
        if(inh[d])
        {
            len=0;pos=1;h[++len]=d;
            for(int k=nxt[d];k!=d;k=nxt[k])h[++len]=k;
            return 0;
        }
        return -1;
    }
    void merge(hh h1,hh h2)
    {
        len=lcm(h1.len,h2.len);pos=1;
        for(int k=1,i=h1.pos,j=h2.pos;k<=len;k++,i=i%h1.len+1,j=j%h2.len+1)
            h[k]=h1.h[i]+h2.h[j];
    }
    int ad(int b){pos=(pos+b-1)%len+1;return h[pos];}
};
struct trnode{int sum,la;hh h;};int w[maxn];
struct Segtree
{
    trnode tr[2*mbit];
    Segtree(){}
    void update(int now)
    {
        tr[now].sum=tr[lc].sum+tr[rc].sum;
        if(tr[lc].la!=-1&&tr[rc].la!=-1)
        {
            tr[now].la=0;
            tr[now].h.merge(tr[lc].h,tr[rc].h);
        }
        else tr[now].la=-1;
    }
    void pushdown(int now)
    {
        if(tr[now].la<=0)return ;
        tr[lc].sum=tr[lc].h.ad(tr[now].la),tr[lc].la=(tr[lc].la+tr[now].la-1)%tr[lc].h.len+1;
        tr[rc].sum=tr[rc].h.ad(tr[now].la),tr[rc].la=(tr[rc].la+tr[now].la-1)%tr[rc].h.len+1;
        tr[now].la=0;
    }
    void bt(int now,int ql,int qr)
    {
        if(ql==qr){tr[now].sum=w[ql],tr[now].la=tr[now].h.insert(w[ql]);return ;}
        bt(lc,ql,mid),bt(rc,mid+1,qr),update(now);
    }
    void change(int now,int ql,int qr,int l,int r)
    {
        if(ql==l&&qr==r&&tr[now].la!=-1){tr[now].sum=tr[now].h.ad(1);tr[now].la++;return ;}
        if(ql==qr){tr[now].la=tr[now].h.insert(nxt[tr[now].sum]),tr[now].sum=nxt[tr[now].sum];return ;}
        pushdown(now);
             if(r<=mid)  change(lc,ql,mid,l,r);
        else if(mid+1<=l)change(rc,mid+1,qr,l,r);
        else change(lc,ql,mid,l,mid),change(rc,mid+1,qr,mid+1,r);
        update(now);
    }
    int getsum(int now,int ql,int qr,int l,int r)
    {
        if(ql==l&&qr==r)return tr[now].sum;
        pushdown(now);
             if(r<=mid)  return getsum(lc,ql,mid,l,r);
        else if(mid+1<=l)return getsum(rc,mid+1,qr,l,r);
        else return getsum(lc,ql,mid,l,mid)+getsum(rc,mid+1,qr,mid+1,r);
    }
}S;

//---------------------------------data structure---------------------------------------------

int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    int n,Q,p;
    scanf("%d%d%d",&n,&Q,&p);
    init(p);
    
    for(int i=1;i<=n;i++)scanf("%d",&w[i]);
    S.bt(1,1,n);
    
    int op,x,y;
    while(Q--)
    {
        scanf("%d%d%d",&op,&x,&y);
        if(op==0)S.change(1,1,n,x,y);
        else printf("%d\n",S.getsum(1,1,n,x,y));
    }
    
    return 0;
}

 

posted @ 2019-02-27 20:42  AKCqhzdy  阅读(171)  评论(0编辑  收藏  举报