POJ 2887 Big String(块状链表)

时间:2024-01-12 16:20:44

题目大意

给一个字符串,长度不超过 106,有两种操作:

  1. 在第 i 个字符的前面添加一个字符 ch

  2. 查询第 k 个位置是什么字符

操作的总数不超过 2000

做法分析

好多不同的做法都可以搞

人生第一个块状链表,记录下

块状链表的思想其实挺简单的,传统的链表每个节点只记录一个字符,块状链表的每个节点记录的是 sqrt(n) 个信息,一个长度为 n 的字符串就被分成了 sqrt(n) 个。这样,查询和插入字符的操作就变成了 sqrt(n)级别的了,对于这题 2000 个操作来讲,时间复杂度还能忍受

这题只有插入和查询操作,所以写起来非常简单

不过我不喜欢使用指针搞来稿去的,所以写的数组形式的

参考代码

 #include <iostream>
#include <cstring>
#include <cstdio> using namespace std; const int N=, LEN=; struct Block_List {
struct Node {
char buff[LEN];
int next, Size;
void init() {
memset(buff, , sizeof buff);
next=-, Size=;
}
} List[N];
int head, tot; void init(char S[]) {
head=tot=;
List[tot++].init();
for(int i=, cur=head; S[i]; cur=List[cur].next) {
for(int j=; j<LEN && S[i]; j++, i++) {
List[cur].buff[j]=S[i];
List[cur].Size++;
}
if(S[i]) {
List[tot].init();
List[cur].next=tot++;
}
}
for(int cur=head; cur!=-; cur=List[cur].next)
if(List[cur].Size==LEN) Split(cur);
} void Split(int id) {
List[tot].init();
for(int i=LEN/; i<LEN; i++) {
List[tot].buff[i-LEN/]=List[id].buff[i];
List[tot].Size++;
List[id].buff[i]=;
List[id].Size--;
}
List[tot].next=List[id].next;
List[id].next=tot++;
} void Insert(int pos, char val) {
int cur=head;
while(pos>List[cur].Size && List[cur].next!=-) {
pos-=List[cur].Size;
cur=List[cur].next;
}
if(pos>=List[cur].Size) List[cur].buff[List[cur].Size]=val;
else {
for(int i=List[cur].Size; i>pos; i--) List[cur].buff[i]=List[cur].buff[i-];
List[cur].buff[pos]=val;
}
List[cur].Size++;
if(List[cur].Size==LEN) Split(cur);
} char Find(int pos) {
int cur=head;
while(pos>List[cur].Size) pos-=List[cur].Size, cur=List[cur].next;
return List[cur].buff[pos-];
}
}; Block_List hehe;
char buff[], S[];
int n; int main() {
// freopen("in", "r", stdin);
scanf("%s", buff);
hehe.init(buff);
scanf("%d", &n);
for(int i=, pos; i<n; i++) {
scanf("%s", buff);
if(buff[]=='I') {
scanf("%s%d", S, &pos);
hehe.Insert(pos-, S[]);
}
else {
scanf("%d", &pos);
printf("%c\n", hehe.Find(pos));
}
}
return ;
}

POJ 2887

题目链接 & AC 通道

POJ 2887 Big String