[2017雅礼7-6]right 分块

来源:互联网 发布:什么是creis中指数据 编辑:程序博客网 时间:2024/06/06 03:35

稍加分(da)析(biao)可知,当p为奇数时,SG(x)=x&1,当p为偶数时,SG(x)=(x%(p+1)==p)?2:((x%(p+1))&1)。
奇数的话相当于区间翻转,区间异或和,直接线段树即可。
偶数的话分块来处理,每个块维护一个add标记和两个有序数组,分别表示奇余数和偶余数,区间加的时候整块的打标记,零散的直接重构,时间复杂度O(n/s+slogs)。查询的时候整块lower_bound找有多少个1和2,1的话应该是奇数数组中还没+add不超过p的,偶数数组中+p超过了add的,2的话根据add的奇偶性来决定在哪个数组查询,零散的也直接重构,时间复杂度O(nlogs/s+slogs)。
所以我也不知道s该取多少,大概250最优吧。

代码:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#define mod (p+1)using namespace std;const int maxn=100100;const int size=220;int n,p,q,a[maxn];inline int ID(int x) {return (x-1)/size+1;}inline int L(int x) {return (x-1)*size+1;}inline int R(int x) {return min(n,x*size);}struct tree{    tree *ls,*rs;    int l,r,sum,rev;    tree()    {        ls=rs=NULL;        sum=rev=0;    }    void pushdown()    {        if(rev)         {            if((r-l+1)&1)sum^=1;            rev=0;            if(ls!=NULL)ls->rev^=1;            if(rs!=NULL)rs->rev^=1;        }    }    void update()    {        ls->pushdown();        rs->pushdown();        sum=ls->sum^rs->sum;    }    void build(int lx,int rx)    {        l=lx;r=rx;        if(l==r) {sum=(a[l]&1);return ;}        int mid=(l+r)>>1;        (ls=new tree)->build(lx,mid);        (rs=new tree)->build(mid+1,rx);        update();    }    void reverse(int lx,int rx)    {        if(l==lx&&r==rx) {rev^=1;return ;}        pushdown();        int mid=(l+r)>>1;        if(rx<=mid) ls->reverse(lx,rx);        else if(lx>mid) rs->reverse(lx,rx);        else {ls->reverse(lx,mid); rs->reverse(mid+1,rx);}        update();    }    int query(int lx,int rx)    {        pushdown();        if(l==lx&&r==rx){return sum;};        int mid=(l+r)>>1;        if(rx<=mid) return ls->query(lx,rx);        else if(lx>mid) return rs->query(lx,rx);        else {return ls->query(lx,mid)^rs->query(mid+1,rx);}    }}*xtr;struct block{    int add,rst[2][400],num[2],id;    void init(int x)    {        memset(rst,0x3f3f3f3f,sizeof(rst));        add=num[0]=num[1]=0;        id=x;    }    void build()    {        int temp=add;        init(id);        for(int i=L(id);i<=R(id);i++)        {            a[i]=(a[i]+temp)%mod;            if(a[i]&1) rst[1][++num[1]]=a[i];            else rst[0][++num[0]]=a[i];        }        sort(rst[1]+1,rst[1]+num[1]+1);        sort(rst[0]+1,rst[0]+num[0]+1);    }    void modify(int x)    {        add=(add+x)%mod;    }    void bmodify(int l,int r,int x)    {        for(int i=l;i<=r;i++)            a[i]=(a[i]+x)%mod;        build();        }    int query()    {        bool pd=(add&1);        int re,lb,ub,lb0,lb1;        lb0=lower_bound(rst[pd]+1,rst[pd]+num[pd]+2,p+1-add)-rst[pd];        lb1=lower_bound(rst[!pd]+1,rst[!pd]+num[!pd]+2,p+1-add)-rst[!pd];        re=((num[pd]-lb0+lb1)&1);        //cout<<"re1:"<<re<<endl;        lb=lower_bound(rst[pd]+1,rst[pd]+num[pd]+2,p-add)-rst[pd];        ub=lb0;         re^=(((ub-lb)&1)<<1);        //cout<<"re2:"<<re<<endl;        return re;          }    int bquery(int l,int r)    {        int re=0;        build();        for(int i=l;i<=r;i++)        {            if(a[i]==p) re^=2;            if(a[i]&1) re^=1;        }           return re;    }}blk[600];int main(){    freopen("right.in","r",stdin);    freopen("right.out","w",stdout);    scanf("%d%d%d",&n,&q,&p);    for(int i=1;i<=n;i++)    {        scanf("%d",&a[i]);        a[i]%=(p+1);    }    if(p&1) (xtr=new tree)->build(1,n);     else        for(int i=1;i<=ID(n);i++)        {            blk[i].init(i);            blk[i].build();        }    while(q--)    {        int opt,l,r,x=0;        scanf("%d%d%d",&opt,&l,&r);        if(opt==0)         {            scanf("%d",&x);            x%=mod;            if(p&1) {if(x&1) xtr->reverse(l,r);}            else             {                if(ID(l)==ID(r)) blk[ID(l)].bmodify(l,r,x);                else                 {                    blk[ID(l)].bmodify(l,R(ID(l)),x);                    blk[ID(r)].bmodify(L(ID(r)),r,x);                    for(int i=ID(l)+1;i<=ID(r)-1;i++)                        blk[i].modify(x);                }            }           }        else        {            if(p&1) printf("%d\n",(xtr->query(l,r)!=0));            else             {                int ans=0;                if(ID(l)==ID(r)) ans^=blk[ID(l)].bquery(l,r);                else                 {                    ans^=blk[ID(l)].bquery(l,R(ID(l)));                    ans^=blk[ID(r)].bquery(L(ID(r)),r);                    for(int i=ID(l)+1;i<=ID(r)-1;i++)                        ans^=blk[i].query();                }                printf("%d\n",(ans!=0));            }        }    }   }
原创粉丝点击