块状链表
块状链表=分块+链表
注意:莫队算法跟这个都是分块算法,莫队算法不可以修改数据的规模,块状链表可以修改数据的规模
int block = 2500; //一个块的标准大小 = sqrt(n)
list<vector<char> > List; //整体是链表,链表的每个元素是一个块
typedef list<vector<char> >::iterator it;
it Find(int &pos) { //返回块,并更新x为这个块中的位置
for (it i = List.begin(); ;i++) { //逐个找链表上的每个块
if(i == List.end() || pos <= i->size()) return i;
pos -= i->size(); //每经过一个块,就更新x
}
}
void Output(int L, int R) { // [L, R)
it L_block = Find(L), R_block = Find(R);
for (it it1 = L_block; ; it1++){ //打印每个块
int a; it1 == L_block ? a=L : a=0; //一个块的起点
int b; it1 == R_block ? b=R : b=it1->size(); //块的终点
for (int i = a; i < b; i++) putchar(it1->at(i));
if(it1 == R_block) break; //迭代器it不能用 <= ,只有 == 和 !=
}
putchar('\n');
}
it Next(it x){return ++x; } //返回下一个块
void Merge(it x) { //合并块x和块x+1
x->insert(x->end(), Next(x)->begin(), Next(x)->end());
List.erase(Next(x));
}
void Split(it x, int pos){ //把第x个块在这个块的pos处分成2块
if (pos == x->size()) return; //pos在这个块的末尾
List.insert(Next(x), vector<char>(x->begin() + pos, x->end()));
//把pos后面的部分划给下一个块
x->erase(x->begin() + pos, x->end()); //删除划出的部分
}
void Update(){ //把每个块重新划成等长的块
for (it i = List.begin(); i != List.end(); i++){
while (i->size() >= (block << 1)) //如果块大于2个block,分开
Split(i, i->size() - block);
while (Next(i) != List.end() && i->size() + Next(i)->size() <= block)
Merge(i); //如果块+下一个块小于block,合并
while (Next(i) != List.end() && Next(i)->empty()) //删除最后的空块
List.erase(Next(i));
}
}
void Insert(int pos, const vector<char>& ch){
it curr = Find(pos);
if (!List.empty()) Split(curr, pos); //把一个块拆为两个
List.insert(Next(curr), ch); //把字符串插到两个块中间
Update();
}
void Delete(int L, int R) { // [L, R)区间的元素
it L_block, R_block;
L_block = Find(L); Split(L_block, L);
R_block = Find(R); Split(R_block, R);
R_block++;
while(Next(L_block) != R_block) List.erase(Next(L_block));
Update();
}
int main(){
vector<char> ch; int len, pos, n;
cin >> n;
while (n--) {
char opt[7]; cin >> opt;
if(opt[0]=='M') cin >> pos;
if(opt[0]=='I'){
ch.clear(); cin >> len; ch.resize(len);
for (int i = 0; i < len; i++){
ch[i] = getchar();
while(ch[i]<32||ch[i]>126) ch[i]=getchar();
} //读一个合法字符
Insert(pos, ch); //把字符串插入到链表中
}
if(opt[0]=='D'){ cin >> len; Delete(pos, pos + len); }
if(opt[0]=='G'){ cin >> len; Output(pos, pos + len); }
if(opt[0]=='P') pos--;
if(opt[0]=='N') pos++;
}
return 0;
}