块状链表

块状链表


  1. 数组来模拟链表
  2. 注意 块的编号和块中数组的下标
  3. belong[]保证编号不重复

例题 Luogu 本文编辑器
  1. belong[]的作用其实相当于记录块的编号 当块 (消失or合并) 时,下一次生成的块就用上一次消失块的编号,首次初始化为不同的就行了
  2. 避免块状链表退化,在删除或者插入后维护2端的块,根据块的大小来决定是 合并还是 割
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e3+10;

struct node {
    int next,size;
    char a[maxn << 1];
}b[maxn << 2];
int n,curpos,cnt,belong[maxn<<2];
char ss[5000000],s[50];

int addi() {
    cnt++;
    return belong[cnt];
}
void dele(int x) {
    belong[cnt] = x;
    cnt--;
}

void init() {
    for (int i=1; i<(maxn<<2); ++i) belong[i] = i;
    cnt = 1;
    b[1].next = -1;
    b[1].size =  0;
}

void add(int x,int y,int len,char c[]) {
    if (y != -1) {
        b[y].next = b[x].next;
        b[y].size = len;
        memcpy(b[y].a,c,len);
    }
    b[x].next = y;
}

void merge(int x,int y) {
    memcpy(b[x].a+b[x].size,b[y].a,b[y].size);
    b[x].size += b[y].size;
    b[x].next = b[y].next;
    dele(y);
}

void split(int k,int pos) {
    if (k==-1 || pos==b[k].size) return;
    add(k,addi(),b[k].size-pos,b[k].a+pos);
    b[k].size = pos;
}

int pos(int &x) {
    int now = 1;
    while (now!=-1 && x>b[now].size) {
        x -= b[now].size;
        now = b[now].next;
    }
    return now; // 块的编号
}

void insert(int p,int len,char c[]) {
    int now = pos(p);
    split(now,p);
    int tot=0,nextblock,st=now;
    while (tot+maxn <= len) {
        nextblock = addi();
        add(now,nextblock,maxn,c+tot);
        tot += maxn;
        now = nextblock;
    }
    if (len - tot) {
        nextblock = addi();
        add(now,nextblock,len-tot,c+tot);
    }
    if (b[now].size+b[nextblock].size<maxn && nextblock!=-1) {
        merge(now,nextblock);
        nextblock = b[now].next;
    }
    if (b[st].size+b[b[st].next].size<maxn && b[st].next!=-1)
        merge(st,b[st].next);
}

void erase(int p,int len) {
    int now = pos(p);
    // 2次split都是为了切割不是整数的部分
    split(now,p);
    int ne = b[now].next;
    while (ne!=-1 && len>b[ne].size) {
        len -= b[ne].size;
        ne = b[ne].next;
    }
    split(ne,len);
    ne = b[ne].next;
    for (int i=b[now].next; i!=ne; i=b[now].next) {
        b[now].next = b[i].next;
        dele(i);
    }
    // 当前ne 就是 now的 下一个
    while (b[now].size+b[ne].size<maxn && ne!=-1) {
        merge(now,ne);
        ne = b[now].next;
    }
}

void get(int p,int len) {
    int k = pos(p);
    // 前处理k块
    int tot = b[k].size - p;
    if (len<tot) tot=len;
    memcpy(ss,b[k].a+p,tot);
    int now = b[k].next;
    // 先弄整块的部分
    while (now!=-1 && len>=tot+b[now].size) {
        memcpy(ss+tot,b[now].a,b[now].size);
        tot += b[now].size;
        now = b[now].next;
    }

    if (len-tot>0 && now!=-1)
        memcpy(ss+tot,b[now].a,len-tot);
    for (int i=0; i<len; ++i)
        cout << ss[i];
    cout << endl;
}

int main() {
    init();
    cin >> n;
    while (n--) {
        int len;
        scanf("%s",s);
        if (s[0]=='M')
            scanf("%d",&curpos);
        else if (s[0] == 'I') {
            scanf("%d",&len); getchar();
            for (int i=0; i<len; ++i) {
                ss[i]=getchar();
                if (ss[i]<32 || ss[i]>126) --i;
            }
            insert(curpos,len,ss);
        } else if (s[0] == 'D') {
            scanf("%d",&len);
            erase(curpos,len);
        } else if (s[0] == 'G') {
            scanf("%d",&len);
            get(curpos,len);
        } else if (s[0] == 'P') {
            curpos--;
        } else if (s[0] == 'N') {
            curpos++;
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值