POJ 3580 SuperMemo(スプレイテンプレート)

問題の意味: デジタル・シーケンスが与えられると、動作の6つのモードがある:
(1)ADDのXYD:X-Yの第二の数を加えた数Dへ。
(2)逆XY:[X、Y]がひっくり返される間隔の数。
(3)XYT REVOLVE:区間[x、y] T番目の回転。
(4)INSERT XP:最初の番号Xの後に挿入P。
(5)DELETE X:X最初の番号を削除します。
(6)MINのXY:クエリー間隔[X、Y]は最小です。
アイデア:区間[L、R]のためのスプレイボードのタイトル、ルーツにL-1スピン、R + 1のスピンは、右の子のルートで、その後、左部分木の1が区間[L、R]である+ R。
我々は、サブツリーに治療期間の後に間隔を置い保存し、削除することができますので、回転部は、前面に前の段落の後、再治療期間を2つのセクションに分かれて、それを交換しています。

#include<cstdio>
#include<iostream>
using namespace std;
const int maxx = 2e5+10;
const int inf = 0x3f3f3f3f;
int ch[maxx][2],fa[maxx],siz[maxx],key[maxx];
int rev[maxx],lazy[maxx],w[maxx],mi[maxx];
int rt,sz;
char s[20];
int get(int x)
{
    return ch[fa[x]][1]==x;
}
void update(int x)
{
    if(!x)return;
    siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
    mi[x]=key[x];
    if(ch[x][0])mi[x]=min(mi[x],mi[ch[x][0]]);
    if(ch[x][1])mi[x]=min(mi[x],mi[ch[x][1]]);
}
void pushdown(int x)
{
    if(!x)return;
    if(rev[x])
    {
        rev[ch[x][0]]^=1;
        rev[ch[x][1]]^=1;
        swap(ch[x][0],ch[x][1]);
        rev[x]=0;
    }
    if(lazy[x])
    {
        lazy[ch[x][0]]+=lazy[x];
        lazy[ch[x][1]]+=lazy[x];
        key[ch[x][0]]+=lazy[x];
        key[ch[x][1]]+=lazy[x];
        mi[ch[x][0]]+=lazy[x];
        mi[ch[x][1]]+=lazy[x];
        lazy[x]=0;
    }
}
void rotate(int x)
{
    int y=fa[x],z=fa[y],k=get(x);
    pushdown(x);pushdown(y);
    ch[y][k]=ch[x][k^1];fa[ch[y][k]]=y;
    ch[x][k^1]=y;fa[y]=x;fa[x]=z;
    if(z)ch[z][ch[z][1]==y]=x;
    update(y);update(x);
}
void splay(int x,int goal) 
{
    for(int y;(y=fa[x])!=goal;rotate(x))
        if(fa[y]!=goal)rotate((get(x)==get(y))?y:x);
    if(goal==0)rt=x; //注意
}
int findkth(int k) //找第k个节点
{
    int x=rt;
    while(1)
    {
        pushdown(x);
        if(k<=siz[ch[x][0]])x=ch[x][0];
        else
        {
            k-=siz[ch[x][0]]+1;
            if(!k)return x;
            x=ch[x][1];
        }
    }
}
int build(int l,int r,int f)
{
    if(l>r)return 0;
    int mid=(l+r)/2;
    int x=++sz;
    fa[x]=f;
    key[x]=w[mid];
    ch[x][0]=build(l,mid-1,x);
    ch[x][1]=build(mid+1,r,x);
    update(x);
    return x;
}
void add(int l,int r,int val) //区间加
{
    int x=findkth(l-1),y=findkth(r+1);
    splay(x,0);splay(y,x);
    int tmp=ch[ch[rt][1]][0];
    key[tmp]+=val;
    mi[tmp]+=val;
    lazy[tmp]+=val;
    update(ch[rt][1]);
    update(rt);     
}
void Insert(int k,int val) //在第k个数后插入值为x的节点
{
    int x=findkth(k),y=findkth(k+1);
    splay(x,0);splay(y,x);
    ch[ch[rt][1]][0]=++sz;
    fa[sz]=ch[rt][1];
    key[sz]=mi[sz]=val;
    siz[sz]=1;
    update(ch[rt][1]);
    update(rt);
}
void Delete(int k) //删除第k个节点
{
    int x=findkth(k-1),y=findkth(k+1);
    splay(x,0);splay(y,x);
    ch[ch[rt][1]][0]=0;
    update(ch[rt][1]);
    update(rt);
}
void Reverse(int l,int r) //区间翻转
{
    int x=findkth(l-1),y=findkth(r+1);
    splay(x,0); //x旋转为根
    splay(y,x); //y旋转为根的右孩子
    //旋转完之后y的左子树为区间[l,r]
    rev[ch[ch[rt][1]][0]]^=1; //lazy标记是否要旋转其左右子树
}
void revolve(int l1,int r1,int l2,int r2) //区间旋转
{
    int x=findkth(l2-1),y=findkth(r2+1);
    splay(x,0);splay(y,x);
    int tmp=ch[ch[rt][1]][0];ch[ch[rt][1]][0]=0; 
    update(ch[rt][1]);update(rt);
    x=findkth(l1-1);y=findkth(l1);
    splay(x,0);splay(y,x);
    ch[ch[rt][1]][0]=tmp;
    fa[tmp]=ch[rt][1];
    update(ch[rt][1]);update(rt);
}
int getmi(int l,int r) //找区间最小值
{
    int x=findkth(l-1),y=findkth(r+1);
    splay(x,0);splay(y,x);
    return mi[ch[ch[rt][1]][0]];
}
int main()
{
    int n,m;
    scanf("%d",&n);
    w[1]=-inf;w[n+2]=inf;
    for(int i=2;i<=n+1;i++)scanf("%d",&w[i]);
    rt=build(1,n+2,0);
    scanf("%d",&m);
    int x,y,z;
    while(m--)
    {
        scanf("%s",s);
        if(s[0]=='A')scanf("%d%d%d",&x,&y,&z),add(x+1,y+1,z);
        else if(s[0]=='I')scanf("%d%d",&x,&y),Insert(x+1,y);
        else if(s[0]=='D')scanf("%d",&x),Delete(x+1);
        else if(s[0]=='M')scanf("%d%d",&x,&y),printf("%d\n",getmi(x+1,y+1));
        else if(s[3]=='E')scanf("%d%d",&x,&y),Reverse(x+1,y+1);
        else
        {
            scanf("%d%d%d",&x,&y,&z);
            z=z%(y-x+1);
            if(z)revolve(x+1,y-z+1,y-z+2,y+1);
        }
    }
    return 0;
}

おすすめ

転載: www.cnblogs.com/HooYing/p/12014227.html