POJ2887 块状数组

1 题意

给出一个长串,然后给出n个操作,操作有两种,在某个位置插入一个字符,或者查询第x个位置上的字符是什么

2分析

(1)

快速输出第x个位置上的字符,像直接存储类数据结构中的数组就可以,但是难在插入一个字符时,后面所有字符都要动,所以不能用普通的数组;

而如果用链表虽然能解决插入不超时的问题,但是因为是顺序存储类结构,所以不能很快的输出第x个位置上的字符。

这里采用块状数组,数组块数*每个块的最大长度>=总的元素+操作个数,即分块以后,每个块都有个增大的空间(让其大于操作个数即可),然后再用一个sum[]数组,统计从第一块到当前块的元素的数量,查找或插入某个元素时,通过输入的x(第x个),利用递增的sum数组进行二分,得到块号,然后x-sum[cur-1]就得到在该块内的第几个,如果查找就返回查找结果,如果输出就只操纵当前快即可。

(2)下面给出两份代码,代码一是块数和块内元素都从1开始;代码二是块数和快内元素都从0开始,后者要在细节上多处理一下。

(3)易错点:

①即块数和块内元素从0还是1开始。

②Init()中,block_num应该是先将输入的串的长度+操作个数,然后再开方;而不是先将串的长度开方之后再加操作个数。个人认为后者导致runtime error的原因是因为这样做的话,导致栈溢出(算了一下,如果是上限1M的栈,就很可能会溢出),相当于每个块的长度都给到最坏情况下需要的长度,而前者只是给每个块的长度设定为平均情况下需要的长度。具体采用哪一种,应该根据题目给出的数据推一下吧,如果不溢出就用后者,如果溢出,那么只能用前者。

summary:

a.

block_len,即各个块的最大长度——Block中dat[]的长度:

在最坏情况下=sqrt(str)+n;

在平均情况下=sqrt(str+n);

b.

block_num,块数:

准确讲,=(str+n)/block_len

结合a中的平均情况来讲,block_num=block_len=sqrt(str+n)、

3

代码一

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;

const int maxn=1010;
int block_len,block_num;//每一块的长度、块数
int n;//操作个数
int sum[maxn];
char str[1000010];
void maintain();
struct Blocks{
    int size_;//个数
    char dat[maxn<<1];//2020;
    void Push_back(char zifu){
        dat[++size_]=zifu;
    }
    void Insert(int pos,char zifu){
        if(pos>size_)   dat[++size_]=zifu;
        else{
            for(int i=++size_;i>pos;i--)
                dat[i]=dat[i-1];
            dat[pos]=zifu;
        }
        maintain();
    }
    //void Delate(){}
    char Query(int pos){
        return dat[pos];
    }
}block[maxn];
void maintain(){
    sum[1]=block[1].size_;
    for(int i=2;i<=block_num;i++)
        sum[i]=sum[i-1]+block[i].size_;
}
void Init(){
    int str_len=strlen(str);
    block_len=block_num=sqrt( (str_len+n)*(1.0) ) ;///in fact,block_len应该是struct Blocks中的dat[]的长度,但是因为不是const,所以提前根据题目条件算出了个最大的数值限定了dat[]的长度
    //block_len=block_num=sqrt( (str_len)*(1.0) )+n ;
    for(int i=1;i<=block_num;i++){
        block[i].size_=0;
        sum[i]=0;
    }
    for(int i=0;i<str_len;i++){
        block[i/block_len +1].Push_back(str[i]);
    }
    maintain();
}
int main()
{
    while(~scanf("%s",str)){
        //gets(str);
        int pos;
        char com[3],s[3];
        scanf("%d",&n);
        Init();
        for(int i=1;i<=n;i++){
            scanf("%s",com);
            int kuai_id,kuai_in_pos;
            if(com[0]=='Q'){
                scanf("%d",&pos);
                kuai_id=lower_bound(sum+1,sum+1+block_num,pos)-sum;
                kuai_in_pos=pos-sum[kuai_id-1];
                cout<<block[kuai_id].Query(kuai_in_pos)<<endl;
            }
            else{
                scanf("%s%d",s,&pos);
                kuai_id=lower_bound(sum,sum+block_num,pos)-sum;
                kuai_in_pos=pos-sum[kuai_id-1];
                block[kuai_id].Insert(kuai_in_pos,s[0]);
            }
        }
    }
    return 0;
}

代码二

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;

const int maxn=1010;
int block_len,block_num;//每一块的长度、块数
int n;//操作个数
int sum[maxn];
char str[1000010];
void maintain();
struct Blocks{
    int size_;//个数
    char dat[maxn<<1];//2020;
    void Push_back(char zifu){
        dat[size_++]=zifu;
    }
    void Insert(int pos,char zifu){
        if(pos>=size_)   dat[size_++]=zifu;
        else{
            for(int i=size_;i>pos;i--)
                dat[i]=dat[i-1];
            dat[pos]=zifu;
            size_++;
        }
        maintain();
    }
    //void Delate(){}
    char Query(int pos){
        return dat[pos];
    }
}block[maxn];
void maintain(){
    sum[0]=block[0].size_;
    for(int i=1;i<=block_num;i++)
        sum[i]=sum[i-1]+block[i].size_;
}
void Init(){
    int str_len=strlen(str);
    block_len=block_num=sqrt( (str_len+n)*(1.0) ) ;///in fact,block_len应该是struct Blocks中的dat[]的长度,但是因为不是const,所以提前根据题目条件算出了个最大的数值限定了dat[]的长度
    //block_len=block_num=sqrt( (str_len)*(1.0) )+n ;
    for(int i=0;i<=block_num;i++){
        block[i].size_=0;
        sum[i]=0;
    }
    for(int i=0;i<str_len;i++){
        block[i/block_len].Push_back(str[i]);
    }
    maintain();
}
int main()
{
        gets(str);
        int pos;
        char com[3],s[3];
        scanf("%d",&n);
        Init();
        for(int i=1;i<=n;i++){
            scanf("%s",com);
            int kuai_id,kuai_in_pos;
            if(com[0]=='Q'){
                scanf("%d",&pos);
                kuai_id=lower_bound(sum,sum+block_num,pos)-sum;
                if(kuai_id==0)
                    kuai_in_pos=(pos-1);
                else
                    kuai_in_pos=pos-sum[kuai_id-1]-1;
                cout<<block[kuai_id].Query(kuai_in_pos)<<endl;//pos-sum[kuai_id-1]是第几个,再-1得到块内的位置
            }
            else{
                scanf("%s%d",s,&pos);
                kuai_id=lower_bound(sum,sum+block_num,pos)-sum;
                 if(kuai_id==0)
                    kuai_in_pos=(pos-1);
                else
                    kuai_in_pos=pos-sum[kuai_id-1]-1;
                block[kuai_id].Insert(kuai_in_pos,s[0]);//pos-sum[kuai_id-1]是第几个,再-1得到块内的位置
            }
        }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值