Codeforces 455D Serega and Fun【解法一】

来源:互联网 发布:大数据时代下的教育 编辑:程序博客网 时间:2024/06/13 20:41

如果不考虑那个奇怪的询问的话,可以简单地用splay树维护序列。但是splay上显然不能维护每种颜色的个数,这样在每个节点上时间和空间都是O(n)的。
我们把给每种颜色的节点单独建一棵splay,每个节点放在两棵splay中,一棵是原序列,一棵是它自己的颜色。接下来考虑如何进行插入、询问和删除操作。
删除操作比较简单,只需要在大splay上找到对应的节点,在两棵树中先旋转到底再自下而上删除。
插入和询问都可以在小splay上走,通过在大splay上的询问就可以知道当前节点在序列中的位置。
复杂度O((n+q)log2n)

#include<cstdio>#include<algorithm>using namespace std;const int maxn=400010;int a[maxn],rt[maxn],val[maxn],size[2][maxn],son[2][maxn][2],fa[2][maxn],num[maxn],n,q,tot;void upd(int u,int f){    size[f][u]=size[f][son[f][u][0]]+size[f][son[f][u][1]]+1;}void rot(int u,int f1,int f2){    int v=son[f2][u][f1],x=son[f2][v][f1^1],f=fa[f2][u];    fa[f2][v]=f;    if (f) son[f2][f][son[f2][f][1]==u]=v;    else    {        if (f2) rt[val[u]]=v;        else rt[0]=v;    }    son[f2][v][f1^1]=u;    fa[f2][u]=v;    son[f2][u][f1]=x;    if (x) fa[f2][x]=u;    upd(u,f2);    upd(v,f2);}void splay(int u,int f){    int x1,x2,f1,f2;    while (fa[f][u])    {        x1=fa[f][u];        f1=(son[f][x1][1]==u);        if (!fa[f][x1]) rot(x1,f1,f);        else        {            x2=fa[f][x1];            f2=(son[f][x2][1]==x1);            if (f1==f2) rot(x2,f2,f),rot(x1,f1,f);            else rot(x1,f1,f),rot(x2,f2,f);        }    }}int getrank(int u){    if (!u) return 0;    splay(u,0);    return size[0][son[0][u][0]]+1;}int getkth(int u,int k){    int x=size[0][son[0][u][0]];    if (x>=k) return getkth(son[0][u][0],k);    if (x+1==k)    {        splay(u,0);        return u;    }    return getkth(son[0][u][1],k-x-1);}void ins0(int u,int v,int k){    size[0][u]++;    if (size[0][son[0][u][0]]>=k-1)    {        if (son[0][u][0]) ins0(son[0][u][0],v,k);        else son[0][u][0]=v,fa[0][v]=u;    }    else    {        if (son[0][u][1]) ins0(son[0][u][1],v,k-size[0][son[0][u][0]]-1);        else son[0][u][1]=v,fa[0][v]=u;    }}void ins1(int u,int v,int k){    size[1][u]++;    if (getrank(u)>=k)    {        if (son[1][u][0]) ins1(son[1][u][0],v,k);        else son[1][u][0]=v,fa[1][v]=u;    }    else    {        if (son[1][u][1]) ins1(son[1][u][1],v,k);        else son[1][u][1]=v,fa[1][v]=u;    }}void Insert(int u,int k){    size[0][u]=size[1][u]=1;    fa[0][u]=fa[1][u]=son[0][u][0]=son[0][u][1]=son[1][u][0]=son[1][u][1]=0;    if (!rt[val[u]]) rt[val[u]]=u;    else ins1(rt[val[u]],u,k);    splay(u,1);    if (!rt[0]) rt[0]=u;    else ins0(rt[0],u,k);    splay(u,0);}void del(int u,int f){    while (son[f][u][0]&&son[f][u][1])        rot(u,size[f][son[f][u][0]]>size[f][son[f][u][1]],f);    for (int i=fa[f][u];i;i=fa[f][i]) size[f][i]--;    int v=son[f][u][0]+son[f][u][1],r=(f?val[u]:0);    if (rt[r]==u)    {        rt[r]=v;        fa[f][v]=0;    }    else    {        if (v) fa[f][v]=fa[f][u];        son[f][fa[f][u]][son[f][fa[f][u]][1]==u]=v;    }    splay(v,f);}void Delete(int u){    del(u,1);    del(u,0);}int qry(int u,int k){    int x=getrank(u),ret;    if (x>k)    {        ret=0;        if (son[1][u][0]) ret+=qry(son[1][u][0],k);        else splay(u,1);    }    else    {        ret=size[1][son[1][u][0]]+1;        if (son[1][u][1]) ret+=qry(son[1][u][1],k);        else splay(u,1);    }    return ret;}int main(){    //freopen("b.in","r",stdin);    int last=0,u,opt,l,r,k;    scanf("%d",&n);    for (int i=1;i<=n;i++)    {        scanf("%d",&val[i]);        Insert(i,i);    }    scanf("%d",&q);    while (q--)    {        scanf("%d%d%d",&opt,&l,&r);        l=(l+last-1)%n+1,r=(r+last-1)%n+1;        if (l>r) swap(l,r);        if (opt==1)        {            u=getkth(rt[0],r);            Delete(u);            Insert(u,l);        }        else        {            scanf("%d",&k);            k=(k+last-1)%n+1;            printf("%d\n",last=(qry(rt[k],r)-qry(rt[k],l-1)));        }    }}