BZOJ_P1507[NOI2003]Editor(块状链表)

13 篇文章 0 订阅
2 篇文章 0 订阅

传送门
Time Limit: 5 Sec Memory Limit: 162 MB
Submit: 2833 Solved: 1148
[Submit][Status][Discuss]
Description

这里写图片描述

Input
输入文件editor.in的第一行是指令条数t,以下是需要执行的t个操作。其中: 为了使输入文件便于阅读,Insert操作的字符串中可能会插入一些回车符,请忽略掉它们(如果难以理解这句话,可以参考样例)。 除了回车符之外,输入文件的所有字符的ASCII码都在闭区间[32, 126]内。且行尾没有空格。 这里我们有如下假定:MOVE操作不超过50000个,INSERT和DELETE操作的总个数不超过4000,PREV和NEXT操作的总个数不超过200000。所有INSERT插入的字符数之和不超过2M(1M=1024*1024),正确的输出文件长度不超过3M字节。DELETE操作和GET操作执行时光标后必然有足够的字符。MOVE、PREV、NEXT操作必然不会试图把光标移动到非法位置。输入文件没有错误。对C++选手的提示:经测试,最大的测试数据使用fstream进行输入有可能会比使用stdio慢约1秒。

Output

输出文件editor.out的每行依次对应输入文件中每条GET指令的输出。

Sample Input
15
Insert 26
abcdefghijklmnop
qrstuv wxy
Move 15
Delete 11
Move 5
Insert 1
^
Next
Insert 1
_
Next
Next
Insert 4
.\/.
Get 4
Prev
Insert 1
^
Move 0
Get 22

Sample Output
.\/.
abcde^_^f.\/.ghijklmno

HINT
Source

第一次打块状链表WAWAWARERERE烦死了!!!
块状链表思想就是分裂合并其实灰常简单

#include<cstdio>
#include<cstdlib> 
#include<cstring>
#include<iostream>
using namespace std;
#define MAXN 2*1024*1024+10
#define N 9000 
struct Node{//结构体 
    char s[N+10];int len;Node* next;
    Node(){s[0]=len=0;next=NULL;}
}*rt;
char str[MAXN],cmd[105];int p;

char buf[MAXN], *ps = buf, *pe = ps+1;
inline void rnext(){//读优 
    if(++ps==pe)
        pe=(ps=buf)+fread(buf,1,sizeof(buf),stdin);
}
inline int get_int(){
    do{rnext();}while(!isdigit(*ps));
    int ans=0;
    do{ans=(ans<<1)+(ans<<3)+*ps-48;rnext();
    }while(isdigit(*ps));
    return ans;
}
inline void get_str(char *s){
    do{rnext();}while(!isalpha(*ps));
    int cnt = 0;
    do{s[cnt++]=*ps;rnext();
    }while(isalpha(*ps));
    s[cnt] = 0;
}
void read(int len){
    int cnt=0;
    while(cnt<len){
        rnext();int ch = *ps;
        if(32<=ch&&126>=ch)str[cnt++]=ch;
    }
    str[cnt] = 0;
}
Node* Find(int pos,int &k){//寻找在第几块 
    int cnt=0;Node *tmp=rt;
    while(tmp->next){
        if(cnt+tmp->len>=pos) break;
        cnt+=tmp->len;tmp=tmp->next;
    }
    k=pos-cnt;return tmp;
}
void Split(Node *u,Node *&r,int k){//分裂 
    r=new Node();
    r->next=u->next;u->next=r;
    strcpy(r->s,u->s+k);
    r->len=u->len-k;u->len=k;u->s[k]=0;
}
void merge(Node *u,Node *r){//合并 
    strcat(u->s,r->s);u->len+=r->len;
    u->next=r->next;free(r);r=NULL;
}
void Insert(int len){//插入 
    int k;Node *u=Find(p,k),*r;
    if(k==u->len) r=u->next;
    else Split(u,r,k);
    Node *tmp=u;int cnt=0;
    while(len-cnt>=N){//处理整块 
        Node *now=new Node();
        strncpy(now->s,str+cnt,N);
        now->s[N]=0;now->len=N;
        now->next=tmp->next;tmp->next=now;
        tmp=now;cnt+=N;
    }
    if(len-cnt){//处理不足一块 
        Node *now=new Node();
        strcpy(now->s,str+cnt);
        now->len=len-cnt;now->next=tmp->next;
        tmp->next=now;tmp=now;cnt=len;
    }
    if(rt!=u&&u->len<=(N>>1)&&u->next&&u->next->len<=(N>>1)){//两个不足一半合并
        if(tmp==u->next) merge(u,u->next),tmp=u;
        else merge(u,u->next);
    }
    if(tmp!=rt&&tmp->len<=(N>>1)&&r&&r->len<=(N>>1)) merge(tmp,r);//两个不足一半合并
}
void Delete(int len){//删除 
    int sk,ek;
    Node *st=Find(p,sk),*sr;Node *ed=Find(p+len,ek),*er;//寻找方格 
    Split(ed,er,ek);Split(st,sr,sk);Node *tmp=st->next;//注意这个先分后面再分前面,由于这个无限WA和RE 
    while(tmp!=er){
        Node *buf=tmp;
        tmp=tmp->next;
        free(buf);
    }
    st->next=er;
    if(st->len<=(N>>1)&&er->len<=(N>>1)) merge(st,er);//两个不足一半合并 
}
void Get(int len){//输出 
    int k,cnt=0;Node* now=Find(p+1,k);k--;
    while(now&&cnt<len){
        while(k<now->len&&cnt<len) putchar(now->s[k]),cnt++,k++;
        now=now->next;k=0;
    }
    putchar('\n');
}
int main(){
    int t,x;t=get_int();
    rt=new Node();p=0;
    while(t--){
        get_str(cmd);
        switch(cmd[0]){
            case 'M':p=get_int();break;
            case 'I':x=get_int();read(x);Insert(x);break;
            case 'D':x=get_int();Delete(x);break;
            case 'G':x=get_int();Get(x);break;
            case 'P':p--;break;
            case 'N':p++;break;
        }
    }
    return 0;
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值