POJ2887 块状数组
来源:互联网 发布:证明贪心算法是最优解 编辑:程序博客网 时间:2024/05/17 04:27
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;}
- POJ2887 块状数组
- Big String-POJ2887块状数组
- 块状链表 poj2887
- POJ2887【块状链表】
- POJ2887 Big String 块状链表
- 【POJ2887】【块状链表】Big String
- poj2887
- POJ2887
- 块状数组
- poj 2887 块状数组
- 块状数组(hdu3207 Highway)
- 初识块状数组/块状链表(讲解+ 例题)
- POJ2887 分块
- uva 12003 Array Transformer (块状数组)
- ZOJ 3635 Cinema in Akiba[ 块状数组 ]
- codefroce D. Powerful array[初识块状数组]
- poj 2887 块状数组/线段树
- 【POJ 2887】Big String(块状数组)
- Javascript闭包
- UVA 1423 Guess(拓扑排序)
- 第十二周 项目5 -迷宫问题之图深度优先遍历加法
- 【codevs】 1814 最长链 树的直径
- Linux内核版本与分类
- POJ2887 块状数组
- HttpURLConnection实现多线程下载资源contentLength()
- html5中的output属性
- javascript eval和JSON之间的联系
- wikioi 1242 布局(奶牛排队) 差分约束
- cmd命令
- 新建servlet运行web后出现classnotfoundexception
- 进阶的基本程序题目
- Centos6.5下安装jdk1.8