块状链表

块状链表


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

例题 Luogu 本文编辑器

  1. belong[]的作用其实相当于记录块的编号 当块 (消失or合并) 时,下一次生成的块就用上一次消失块的编号,首次初始化为不同的就行了
  2. 避免块状链表退化,在删除或者插入后维护2端的块,根据块的大小来决定是 合并还是 割
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#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;
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!