NOIP模拟题[双向链表][延时更新][回收空间]EDITOR

5.1 题意描述
九发明了一个完美的文本编辑器。这个编辑器拥有两个光标(cursor),所以九能够同时
在两处地方插入和删除文本。这个编辑器除了正常的编辑功能以外,还有一些只有九才知道用
处的功能,例如翻转两个光标之间的文本。某一天,九把自己的完美文本编辑器给弄丢了,但
是她还有好多好多文本需要处理。于是她想请聪明又智慧的你帮她实现完美文本编辑器的一
些功能。
功能列表如下:
功能名称命令格式说明
< (move left) < w
w 为一个字符,“L”或“R”,表示左光标还是右光标(下同)。
该命令将选定光标向左移动,如果已经是最左端则不移动。
命令执行成功时输出“T”,若光标已经在最左端,则输出“F”。
(move right) > w
w 同上。
与< 命令不同的是,该命令将光标向右移动。
命令执行成功时输出“T”,若光标已经在最右端,则输出“F”。
I (insert) I w c
w 同上。
c 是一个可见字符(33 ascii 码 126),代表在该光标左侧插入该字符。
该命令始终输出“T”。
D (delete) D w
w 同上。
代表删除该光标右侧的一个字符。
命令执行成功时输出“T”,若光标右侧没有字符输出“F”。
R (reverse) R
代表翻转左光标和右光标之间的字符。
该命令只有左光标在右光标左侧时才能执行。
(两光标重合时也不能执行)
命令执行成功时输出“T”,否则输“F”。
S (show) S 代表显示当前处理的文本。
该命令只输出文本,不输出“T”和“F”。
开始时文本编辑器中有一定内容,左光标在第一个字符左,右光标在最后一个字符右。
注意:在插入和删除操作中,没有被操作的光标与文本的相对左右位置保持不变。特别
地,若两个光标重叠,操作后也仍然重叠。
5.2 输入格式
第一行是初始时文本编辑器内容。
第二行是一个正整数N,N 表示操作次数。
接下来有N 行,每行有一个命令,命令格式如上方表格。
5.3 输出格式
对于每个命令,按上方表格要求执行并输出。
5.4 样例输入
goodykc
11
I R u
I R l
L
L
L
L
R
D R
< R
D R
S
5.5 样例输出
T
T
T
T
T
T
T
F
T
T
goodluck
5.6 样例解释
[goodykc]
[goodykcu]
[goodykcul]
g[oodykcul]
go[odykcul]
goo[dykcul]
good[ykcul]
good[lucky]
good[lucky](光标右边没有字符,失败删除)
good[luck]y
good[luck]
goodluck
5.7 数据规模与约定
• 对于40% 的数据:1 N , 初始文本长度 100,数据不包含翻转(Reverse)操作;
• 另有30% 的数据:1 N , 初始文本长度 105,数据不包含翻转(Reverse)操作;
• 另有20% 的数据:1 N , 初始文本长度 105,数据包含翻转(Reverse)操作;
• 对于100% 的数据:1 N , 初始文本长度 4 106,输出文件大小 20MB;

70%数据忽略反转操作可以直接双向链表O(n)过掉,然而向我这种蒟蒻连暴力链表都打不来TAT
90%用SPLAL翻转O(nlogn),平衡树我还是不会写啊,记得填掉这个坑
100%数据链表加延时更新。显然的,翻转区间L-R时只有L和R的前驱后继会完全变化,而L~R只是前驱和后继交换了位置。所以我们只需先将L,R处理好,之后需要移动光标,插入和输出的时候当找到某个节点后继的前驱不等于这个结点的时候,则代表找到了延时更新标记,swap(pre,nxt)即可。
这里还可以有回收空间的操作,删除掉一个结点,就把它放入队列,之后扩展新节点时直接取这个结点的下标即可

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#define pre(x) node[x].pre
#define nxt(x) node[x].nxt
#define val(x) node[x].val
using namespace std;
const int maxn=1e7+5,INF=0x7f7f7f7f;
int m,maxnode,pos[2],cnt[2],BEGIN,END,q;
char T[maxn];
queue<int>que;
struct data
{
    int pre,nxt;
    char val;
    inline void clear() {pre=nxt=0; val='\0';}
}node[maxn];
inline int Require()
{
    if (!que.empty())
    {
        int temp=que.front(); que.pop();
        return temp;
    }
    return ++maxnode;
}
inline void Recycle(int x)
{
    que.push(x);
    node[x].clear();
}
inline void L_move(int op)
{
    if (pos[op]==BEGIN)
    {
        putchar('F');
        return ;
    }
    int u=pos[op],v=pre(u);
    if (nxt(v)^u) swap(pre(v),nxt(v));
    pos[op]=v; cnt[op]--;
    putchar('T');
}
inline void R_move(int op)
{
    if (nxt(pos[op])==END)
    {
        putchar('F');
        return ;
    }
    int u=nxt(pos[op]),v=nxt(u);
    if(pre(v)^u) swap(pre(v),nxt(v));
    pos[op]=u; cnt[op]++;
    putchar('T');
}
inline void Insert(int op,char ch)
{
    int u=pos[op],v=nxt(u);
    int cur=Require();
    val(cur)=ch; pre(cur)=u; nxt(cur)=v;
    nxt(u)=cur; pre(v)=cur;
    if (cnt[op^1]>=cnt[op]) cnt[op^1]++;
    pos[op]=cur; cnt[op]++;
    if (pos[op^1]==u) pos[op^1]=cur;
    putchar('T');
}
inline void Delete(int op)
{
    if (nxt(pos[op])==END)
    {
        putchar('F');
        return;
    }
    int u=pos[op],v=nxt(u),w=nxt(v);
    if(pre(w)^v) swap(pre(w),nxt(w));
    Recycle(v);
    nxt(u)=w; pre(w)=u;
    if(cnt[op^1]>cnt[op]) cnt[op^1]--;
    if(pos[op^1]==v) pos[op^1]=u; 
    putchar('T');
}
inline void Reserve()
{
    if (cnt[1]<=cnt[0])
    {
        putchar('F');
        return;
    }
    if (cnt[1]==cnt[0]+1)
    {
        putchar('T');
        return;
    }
    int p1=pos[0],p2=nxt(p1),p3=pos[1],p4=nxt(p3);
    swap(pre(p2),nxt(p2)); swap(pre(p3),nxt(p3));
    nxt(p1)=p3; pre(p3)=p1;
    nxt(p2)=p4; pre(p4)=p2;
    pos[1]=p2; 
    putchar('T');
}
inline void Show()
{
    int root=BEGIN;
    do
    {
        if(pre(nxt(root))^root) swap(pre(nxt(root)),nxt(nxt(root)));
        root=nxt(root);
        putchar(val(root));
    }while(nxt(root)^END);
}
void init()
{
    int len=strlen(T);
    BEGIN=1,END=2;
    maxnode=2;
    for (int i=0;i<len;i++)
    {
        val(++maxnode)=T[i];
        pre(maxnode)=i==0?BEGIN:maxnode-1;
        nxt(maxnode)=i==len-1?END:maxnode+1;
    }
    pre(BEGIN)=-1; nxt(BEGIN)=3;
    pre(END)=maxnode; nxt(END)=-1;
    pos[0]=BEGIN; pos[1]=maxnode;
    cnt[0]=0; cnt[1]=len;
}
inline char read()
{
    char ch=getchar();
    while(ch==' '||ch=='\n') ch=getchar();
    return ch;
}
int main()
{
    freopen("editor.in","r",stdin);
    freopen("editor.out","w",stdout);
    scanf("%s",T);
    init();
    scanf("%d",&q);
    while (q--)
    {
        char op=read();
        char temp;
        switch (op)
        {
            case '<':L_move(read()=='R');break;
            case '>':R_move(read()=='R');break;
            case 'I':temp=read(); Insert(temp=='R',read());break;
            case 'D':Delete(read()=='R');break;
            case 'R':Reserve();break;
            case 'S':Show();break;
        }
        putchar('\n');
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值