BZOJ 1269 文本编辑器editor(splay)

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1269

题意:维护一个文本编辑器,初始时文本为空,光标在最开始位置也就是0.操作有以下:

 

 

 

 

 

 

 

思路:显然光标的移动是很简单的,只需要记录即可。那么剩下的操作实际还有四个:(设A为根,B为根右子树,C为B左子树)

(1)插入:插入位置在pos,只需要将pos调整到A,将pos+1调整到B,则其新的串插入C即可(当然插入的串要先建立一个子树);

(2)删除:设删除位置为pos,长度n,则删除区间实际是[pos+1,pos+n],则只需要将pos调整到A,pos+n+1调整到B,则C就是删除的区间;

(3)翻转:设翻转位置为pos,长度n,则翻转区间实际是[pos+1,pos+n],则只需要将pos调整到A,pos+n+1调整到B,则C就是翻转的区间,标记其翻转即可;

(4)查找第k个位置:节点记录一个本子树包含节点个数,则递归查找即可。

另外,对于区间的操作,为方便,在原串的两端分别增加一个元素更容易操作。




int tot,root,L[N],R[N],f[N],s[N],isRev[N];
char k[N];


inline void pushUp(int x)
{
    if(x) s[x]=s[L[x]]+s[R[x]]+1;
}




inline void pushDown(int x)
{
    if(!x) return;
    if(isRev[x])
    {
        if(L[x]) isRev[L[x]]^=1;
        if(R[x]) isRev[R[x]]^=1;
        swap(L[x],R[x]);
        isRev[x]=0;
    }
}


inline void zig(int x)
{
    int y=f[x],z=f[y];
    if(z) L[z]==y?L[z]=x:R[z]=x;
    f[x]=z;
    L[y]=R[x];
    if(R[x]) f[R[x]]=y;
    R[x]=y;
    f[y]=x;
    pushUp(y);
    pushUp(x);
    if(root==y) root=x;
}




inline void zag(int x)
{
    int y=f[x],z=f[y];
    if(z) L[z]==y?L[z]=x:R[z]=x;
    f[x]=z;
    R[y]=L[x];
    if(L[x]) f[L[x]]=y;
    L[x]=y;
    f[y]=x;
    pushUp(y);
    pushUp(x);
    if(root==y) root=x;
}




inline void splay(int x,int goal)
{
    int y;
    while((y=f[x])!=goal)
    {
        if(f[y]!=goal)
        {
            pushDown(f[y]);
            pushDown(y);
            pushDown(x);
            if(L[f[y]]==y) L[y]==x?(zig(y),zig(x)):(zag(x),zig(x));
            else R[y]==x?(zag(y),zag(x)):(zig(x),zag(x));
        }
        else
        {
            pushDown(y);
            pushDown(x);
            L[y]==x?zig(x):zag(x);
        }
    }
}




int select(int k)
{
    int x=root;
    pushDown(x);
    while(s[L[x]]+1!=k)
    {
        s[L[x]]>=k?x=L[x]:(k-=s[L[x]]+1,x=R[x]);
        pushDown(x);
    }
    return x;
}




int newNode(char key,int p)
{
    int e=++tot;
    k[e]=key; f[e]=p; s[e]=1;
    return e;
}




int buildTree(int left,int right,char str[],int p)
{
    if(left>right) return 0;
    int mid=(left+right)>>1;
    int e=newNode(str[mid],p);
    L[e]=buildTree(left,mid-1,str,e);
    R[e]=buildTree(mid+1,right,str,e);
    pushUp(e);
    return e;
}


void insert(int pos,int n,char str[])
{
    int x=select(pos+1),y=select(pos+2);
    splay(x,0);
    splay(y,x);
    L[y]=buildTree(1,n,str,y);
    splay(y,0);
}




void del(int pos,int n)
{
    int x=select(pos+1),y=select(pos+1+n+1);
    splay(x,0);
    splay(y,x);
    L[y]=0;
    splay(y,0);
}




void reverse(int pos,int n)
{
    int x=select(pos+1),y=select(pos+1+n+1);
    splay(x,0);
    splay(y,x);
    isRev[L[y]]^=1;
}




void init()
{
    root=newNode('$',0);
    R[root]=newNode('$',root);
    pushUp(root);
}


int n,curPos,x;
char str[N],op[20];


void getStr()
{
    char c=getchar();
    while(c!='\n') c=getchar();
    gets(str+1);
}




int main()
{
    init();RD(n);
    while(n--)
    {
        RD(op);
        if(op[0]=='M') RD(x),curPos=x;
        else if(op[0]=='I') RD(x),getStr(),insert(curPos,x,str);
        else if(op[0]=='D') RD(x),del(curPos,x);
        else if(op[0]=='R') RD(x),reverse(curPos,x);
        else if(op[0]=='G') putchar(k[select(curPos+2)]),puts("");
        else if(op[0]=='P') curPos--;
        else curPos++;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值