BZOJ 1269 [AHOI2006]文本编辑器editor 伸展树splay

      题目也是中文的就不说题意了。新开一个变量pos记录光标在第pos个节点,因为头尾同样要虚拟一个头结点和尾结点,所以光标也就是指向当前序列的第pos-1个字符。move,prev,next直接修改pos的值就行,剩下的就都是伸展树的基本操作了。insert操作就把pos伸展到根,pos+1伸展到根的下边,向pos+1的左孩子循环添加节点就行,添加完记得自底而上pushup回来。rotate就把pos伸展到根,pos+c+1伸展到根的下边,旋转pos+c+1的左子树,delete也同样把目标区间旋转到根的右孩子的左孩子,删掉即可,get就把pos伸展到根,输出根的值。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <memory.h>
#include <cmath>
#include <string>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn=2000000+50000;
int pre[maxn],ch[maxn][2];
int flip[maxn];
int size[maxn];
char key[maxn];
int root,n,tot;
int m,p,q,r,t,tt;
struct splaytree
{
    int pos;
    void pushup(int r)
    {
        size[r]=1+size[ch[r][0]]+size[ch[r][1]];
    }
    void go_f(int r)
    {
        flip[r]^=1;
        swap(ch[r][0],ch[r][1]);
    }
    void pushdown(int r)
    {
        if (flip[r])
        {
            go_f(ch[r][0]);
            go_f(ch[r][1]);
            flip[r]=0;
        }
    }
    void rotate(int x,int kind)
    {
        int y=pre[x];
        pushdown(y);
        pushdown(x);
        ch[y][!kind]=ch[x][kind];
        pre[ch[x][kind]]=y;
        if (pre[y])
        {
            ch[pre[y]][ch[pre[y]][1]==y]=x;
        }
        pre[x]=pre[y];
        ch[x][kind]=y;
        pre[y]=x;
        pushup(y);
        pushup(x);
    }
    void splay(int x,int tgt)
    {
        pushdown(x);
        while(pre[x]!=tgt)
        {
            int y=pre[x];
            pushdown(pre[y]);
            pushdown(y);
            pushdown(x);
            if (pre[pre[x]]==tgt)
            {
                rotate(x,ch[pre[x]][0]==x);
            }
            else
            {
                int kind=ch[pre[y]][0]==y;
                if (ch[y][kind]==x)
                {
                    rotate(x,kind^1);
                    rotate(x,kind);
                }
                else
                {
                    rotate(y,kind);
                    rotate(x,kind);
                }
            }
        }
        pushup(x);
        if (tgt==0) root=x;
    }
    void select(int k,int tgt)
    {
        int rt=root;
        pushdown(rt);
        while(true)
        {
            if (k<=size[ch[rt][0]]) rt=ch[rt][0];
            else if (k==size[ch[rt][0]]+1) break;
            else k-=(size[ch[rt][0]]+1),rt=ch[rt][1];
            pushdown(rt);
        }
        splay(rt,tgt);
    }
    void newnode(int &r,int father,char k)
    {
        r=++tot;
        pre[r]=father;
        size[r]=1;
        flip[r]=0;
        key[r]=k;
        ch[r][0]=ch[r][1]=0;
    }
    void init()
    {
        tot=root=0;
        newnode(root,0,0);
        newnode(ch[root][1],root,0);
        pushup(ch[root][1]);
        pushup(root);
        pos=1;
    }
    void Flip(int c)
    {
        select(pos,0);
        select(pos+c+1,root);
        go_f(ch[ch[root][1]][0]);
    }
    void Move(int c)
    {
        pos=c;
    }
    void Insert(int c,char *s)
    {
        select(pos,0);
        select(pos+1,root);
        int rt=ch[root][1];
        newnode(ch[rt][0],rt,*s);
        ++s;
        rt=ch[rt][0];
        for (;*s; rt=ch[rt][1],++s)
        {
            newnode(ch[rt][1],rt,*s);
        }
        while (pre[rt])
        {
            pushup(rt);
            rt=pre[rt];
        }
        pushup(root);
    }
    void Del(int c)
    {
        select(pos,0);
        select(pos+c+1,root);
        int t=ch[ch[root][1]][0];
        pre[t]=0;
        ch[ch[root][1]][0]=0;
        pushup(ch[root][1]);
        pushup(root);
    }
    void Get()
    {
        select(pos+1,0);
        printf("%c\n",key[root]);
    }
    void Prev()
    {
        pos--;
    }
    void Next()
    {
        pos++;
    }
    void print(int rt)
    {
        if (rt==0) return ;
        pushdown(rt);
        print(ch[rt][0]);
        if (key[rt]) printf("%c",key[rt]);
        print(ch[rt][1]);
    }
    void Show()
    {
        print(root);
        puts("");
    }
}spt;
char cmd[100];
char s[2*1050*1050];
string ss;
int main()
{
//    freopen("in.txt","r",stdin);
    scanf("%d",&n);
    spt.init();
    for (int i=1; i<=n; i++)
    {
        scanf("%s",cmd);
        if (cmd[0]=='I')
        {
            scanf("%d",&m);
            getchar();
            gets(s);
            spt.Insert(m,s);
        }
        else if (cmd[0]=='M')
        {
            scanf("%d",&m);
            spt.Move(m+1);
        }
        else if (cmd[0]=='N')
        {
            spt.Next();
        }
        else if (cmd[0]=='P')
        {
            spt.Prev();
        }
        else if (cmd[0]=='R')
        {
            scanf("%d",&m);
            spt.Flip(m);
        }
        else if (cmd[0]=='G')
        {
            spt.Get();
        }
        else if (cmd[0]=='D')
        {
            scanf("%d",&m);
            spt.Del(m);
        }
        else spt.Show();
    }
    return 0;
}


你可能感兴趣的:(BZOJ 1269 [AHOI2006]文本编辑器editor 伸展树splay)