4.6块状链表

块状链表

块状链表=分块+链表

注意:莫队算法跟这个都是分块算法,莫队算法不可以修改数据的规模,块状链表可以修改数据的规模

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值