HYSBZ - 1269 文本编辑器editor (Splay 字符串的区间操作)

文本编辑器editor

Time Limit: 10000MS   Memory Limit: 165888KB   64bit IO Format: %lld & %llu

Description

这些日子,可可不和卡卡一起玩了,原来可可正废寝忘食的想做一个简单而高效的文本编辑器。你能帮助他吗?为了明确任务目标,可可对“文本编辑器”做了一个抽象的定义:   文本:由0个或多个字符构成的序列。这些字符的ASCII码在闭区间[32, 126]内,也就是说,这些字符均为可见字符或空格。光标:在一段文本中用于指示位置的标记,可以位于文本的第一个字符之前,文本的最后一个字符之后或文本的某两个相邻字符之间。文本编辑器:为一个可以对一段文本和该文本中的一个光标进行如下七条操作的程序。如果这段文本为空,我们就说这个文本编辑器是空的。 编写一个程序:? 建立一个空的文本编辑器。? 从输入文件中读入一些操作指令并执行。? 对所有执行过的GET操作,将指定的内容写入输出文件。

Input

输入文件中第一行是指令条数N,以下是需要执行的N个操作。除了回车符之外,输入文件的所有字符的ASCII码都在闭区间[32, 126]内。且行尾没有空格。

Output

依次对应输入文件中每条GET指令的输出,不得有任何多余的字符。

Sample Input

10
Insert 13
Balanced eert
Move 2
Delete 5
Next
Insert 7
editor
Move 0
Get
Move 11
Rotate 4
Get

Sample Output

B
t

Hint

对输入数据我们有如下假定:? MOVE操作不超过50 000个,INSERT、DELETE和ROTATE操作作的总个数不超过6 000,GET操作不超过20 000个,PREV和NEXT操作的总个数不超过20 000。? 所有INSERT插入的字符数之和不超过2M(1M=1 024*1 024)。? DELETE操作、ROTATE操作和GET操作执行时光标后必然有足够的字符。MOVE、PREV、NEXT操作不会把光标移动到非法位置。? 输入文件没有错误。

分析:Splay的基本操作,对于move光标的操作,用一个pos指针来模拟就行了;对于插入操作,先进行伸展操作将pos所在位置移到根节点的位置,将pos+1的位置移到根节点右子树的位置,然后在其左子树插入字符串就行了,对于删除和翻转也是相同的做法

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;

#define Key_value ch[ch[root][1]][0]
const int MAXN = 2*1024*1024+10;
const int INF = 0X3F3F3F3F;
int fa[MAXN],ch[MAXN][2],sz[MAXN],rev[MAXN];
char key[MAXN];
int root,tot1;
int s[MAXN],tot2;//内存池、内存池容量

int pos;
char str[MAXN];
int n;

void NewNode(int &r,int pre,char k)
{
    if(tot2) r=s[tot2--];
    else r=++tot1;
    ch[r][0]=ch[r][1]=0;
    fa[r]=pre;
    sz[r]=1;
    rev[r]=0;
    key[r]=k;
}
void Update_Rev(int r)
{
    if(r==0) return;
    swap(ch[r][0],ch[r][1]);
    rev[r]^=1;
}
void Push_Up(int r)
{
    sz[r]=sz[ch[r][0]]+sz[ch[r][1]]+1;
}
void Push_Down(int r)
{
    if(rev[r])
    {
        Update_Rev(ch[r][0]);
        Update_Rev(ch[r][1]);
        rev[r]=0;
    }
}
void Build(int &x,int l,int r,int pre)
{
    if(l>r) return;
    int mid=(l+r)/2;
    NewNode(x,pre,str[mid]);
    Build(ch[x][0],l,mid-1,x);
    Build(ch[x][1],mid+1,r,x);
    Push_Up(x);
}
void Init()
{
    pos=0;
    root=tot1=tot2=0;
    ch[root][0]=ch[root][1]=sz[root]=rev[root]=fa[root]=0;
    NewNode(root,0,‘ ‘);
    NewNode(ch[root][1],root,‘ ‘);
    //Build(Key_value,1,n,ch[root][1]);
    Push_Up(ch[root][1]);
    Push_Up(root);
}
void Rotate(int x,int d)
{
    int y=fa[x];
    Push_Down(y);
    Push_Down(x);
    ch[y][!d]=ch[x][d];
    fa[ch[x][d]]=y;
    if(fa[y]) ch[fa[y]][ch[fa[y]][1]==y]=x;
    fa[x]=fa[y];
    ch[x][d]=y;
    fa[y]=x;
    Push_Up(y);
}
//伸展操作,将r调整到goal下面
void Splay(int r,int goal)
{
    Push_Down(r);
    while(fa[r]!=goal)
    {
        if(fa[fa[r]]==goal)
        {
            //这题有反转操作,需要先push_down,在判断左右孩子
            Push_Down(fa[r]);
            Push_Down(r);
            Rotate(r,ch[fa[r]][0]==r);
        }
        else
        {
            //这题有反转操作,需要先push_down,在判断左右孩子
            Push_Down(fa[fa[r]]);
            Push_Down(fa[r]);
            Push_Down(r);
            int y=fa[r];
            int d=(ch[fa[y]][0]==y);
            //两个方向不同,则先左旋再右旋
            if(ch[y][d]==r)
            {
                Rotate(r,!d);
                Rotate(r,d);
            }
            //两个方向相同,相同方向连续两次
            else
            {
                Rotate(y,d);
                Rotate(r,d);
            }
        }
    }
    Push_Up(r);
    if(goal==0) root=r;
}
int Get_Kth(int r,int k)
{
    Push_Down(r);
    int t=sz[ch[r][0]]+1;
    if(t==k)return r;
    if(t>k)return Get_Kth(ch[r][0],k);
    else return Get_Kth(ch[r][1],k-t);
}
void Erase(int r)
{
    if(r)
    {
        s[++tot2]=r;
        Erase(ch[r][0]);
        Erase(ch[r][1]);
    }
}
void update_int(int len)
{
    Splay(Get_Kth(root,pos+1),0);
    Splay(Get_Kth(root,pos+2),root);
    Build(Key_value,0,len-1,ch[root][1]);
    Push_Up(ch[root][1]);
    Push_Up(root);
}
void update_del(int len)
{
    Splay(Get_Kth(root,pos+1),0);
    Splay(Get_Kth(root,pos+len+2),root);
    Erase(Key_value);
    fa[Key_value]=0;
    Key_value=0;
    Push_Up(ch[root][1]);
    Push_Up(root);
}
void update_rot(int len)
{
    Splay(Get_Kth(root,pos+1),0);
    Splay(Get_Kth(root,pos+len+2),root);
    Update_Rev(Key_value);
    Push_Up(ch[root][1]);
    Push_Up(root);
}

int main()
{
    int x;
    char op[20];
    scanf("%d",&n);
    Init();
    while(n--)
    {
        scanf("%s",op);
        if(strcmp(op,"Insert")==0)
        {
            scanf("%d",&x);
            getchar();
            gets(str);
            //cout<<str<<endl;
            update_int(x);
        }
        else if(strcmp(op,"Delete")==0)
        {
            scanf("%d",&x);
            update_del(x);
        }
        else if(strcmp(op,"Rotate")==0)
        {
            scanf("%d",&x);
            update_rot(x);
        }
        else if(strcmp(op,"Get")==0)
        {
            printf("%c\n",key[Get_Kth(root,pos+2)]);
        }
        else if(strcmp(op,"Move")==0)
        {
            scanf("%d",&x);
            pos=x;
        }
        else if(strcmp(op,"Next")==0) pos++;
        else if(strcmp(op,"Prev")==0) pos--;
    }
    return 0;
}
时间: 2024-11-03 01:29:47

HYSBZ - 1269 文本编辑器editor (Splay 字符串的区间操作)的相关文章

[AHOI2006]文本编辑器editor (Splay tree)

我感觉伸展树越来越模版了,没想到这么轻易的就过了... 把光标位置标记为pos MOVE:pos++或者pos-- INSERT:把光标旋转至根部,然后把光标后一个字母旋转至根的右子树,然后把insert的内容插入到root的右子树的左子树 ROTATE:把光标旋转至根部,然后把光标后一个字母旋转至根的右子树,然后把rev[root10]取反 GET:得到光标位置的后继,可以GET_KTH后然后GET_NEXT,也可以直接旋转,或者旋转后GET_MIN PREV,NEXT:都只需要改变光标位置变

BZOJ 1269: [AHOI2006]文本编辑器editor( splay )

splay..( BZOJ 1507 题目基本相同..双倍经验 ) ----------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #define rep( i , n ) for( int i = 0 ; i <

【BZOJ1269】[AHOI2006]文本编辑器editor Splay

[BZOJ1269][AHOI2006]文本编辑器editor Description 这些日子,可可不和卡卡一起玩了,原来可可正废寝忘食的想做一个简单而高效的文本编辑器.你能帮助他吗?为了明确任务目标,可可对"文本编辑器"做了一个抽象的定义:   文本:由0个或多个字符构成的序列.这些字符的ASCII码在闭区间[32, 126]内,也就是说,这些字符均为可见字符或空格.光标:在一段文本中用于指示位置的标记,可以位于文本的第一个字符之前,文本的最后一个字符之后或文本的某两个相邻字符之间

[bzoj1269][AHOI2006文本编辑器editor] (splay模版题)

Description 这些日子,可可不和卡卡一起玩了,原来可可正废寝忘食的想做一个简单而高效的文本编辑器.你能帮助他吗?为了明确任务目标,可可对“文本编辑器”做了一个抽象的定义:   文本:由0个或多个字符构成的序列.这些字符的ASCII码在闭区间[32, 126]内,也就是说,这些字符均为可见字符或空格.光标:在一段文本中用于指示位置的标记,可以位于文本的第一个字符之前,文本的最后一个字符之后或文本的某两个相邻字符之间.文本编辑器:为一个可以对一段文本和该文本中的一个光标进行如下七条操作的程

【BZOJ】【1269】【AHOI2006】文本编辑器editor

Splay Splay序列维护的模板题了……为了便于处理边界情况,我们可以先插入两个空格当作最左端和最右端,然后……其实本题主要考察的就是Build.splay和Findkth这三个操作,我们可以实现一个splay(x,s)操作,使x结点旋转到s结点的下方(如果s为0则x旋转到根),这样可以方便地提取出要处理的区间. 这份模板我还是比较满意的,因为写的没那么长…… 1 /**************************************************************

1269: [AHOI2006]文本编辑器editor

1269: [AHOI2006]文本编辑器editor Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4718  Solved: 1807[Submit][Status][Discuss] Description 这些日子,可可不和卡卡一起玩了,原来可可正废寝忘食的想做一个简单而高效的文本编辑器.你能帮助他吗?为了明确任务目标,可可对“文本编辑器”做了一个抽象的定义:   文本:由0个或多个字符构成的序列.这些字符的ASCII码在闭区间[32,

BZOJ 1269 【AHOI2006】 文本编辑器editor

题目链接:文本编辑器editor 这道题没啥好说的,直接上\(Splay\)就行了,板子题-- 但是我某个地方忘了下放标记导致调了一晚上 保存一发板子: #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define File(s) freopen(s".in","r",std

NOI2003 文本编辑器editor

1507: [NOI2003]Editor Time Limit: 5 Sec  Memory Limit: 162 MBSubmit: 1908  Solved: 738[Submit][Status] Description Input 输入文件editor.in的第一行是指令条数t,以下是需要执行的t个操作.其中: 为了使输入文件便于阅读,Insert操作的字符串中可能会插入一些回车符,请忽略掉它们(如果难以理解这句话,可以参考样例). 除了回车符之外,输入文件的所有字符的ASCII码都在

AHOI2006文本编辑器editor

1269: [AHOI2006]文本编辑器editor Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1885  Solved: 683[Submit][Status] Description 这些日子,可可不和卡卡一起玩了,原来可可正废寝忘食的想做一个简单而高效的文本编辑器.你能帮助他吗?为了明确任务目标,可可对“文本编辑器”做了一个抽象的定义:   文本:由0个或多个字符构成的序列.这些字符的ASCII码在闭区间[32, 126]内,也就是说