[BZOJ1507][NOI2003]Editor(块状链表)
2016-08-24 17:38
381 查看
题目描述
传送门题解
块状链表模板题,主要能实现几个简单的操作:添加一段区间,删除一段区间,输出一段区间内的元素。操作的主要过程如下:
插入:找到光标所在的块以及光标在块中的位置,将这个块从这个位置分成两半。将需要插入的区间分成若干个块插入在中间。将碎块合并。
删除:分别找到删除的区间的左右端点所在的块和它们在块中的位置,将这两个块从各自的位置分成两半。将中间的块删除。将碎块合并。
输出:找到光标所在的块和它在块中的位置,向后将一段一段的块拼成给定长度的块。
代码
// BZOJ 1507 #include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; const int N=1<<25; const int blocksize=20000; const int blocknum=N/blocksize*3; int T,_; int cur; char str[5000005],opt[100]; queue <int> q; struct node { char data[blocksize+111]; int len,nxt; }a[blocknum+1000]; void init() { for (int i=1;i<=blocknum;++i) q.push(i); a[0].len=0; a[0].nxt=-1; } void read(int len) { int i=-1; while (i<len-1) { i++; char c=getchar(); str[i]=c; if (c<32||c>126) i--; } } //新开一个块的节点 int newnode() { int temp=q.front(); q.pop(); return temp; } //回收块的节点 void delnode(int t) { q.push(t); } //找到pos所在的块,并使pos表示在当前块中的位置 void find(int &pos,int &now) { for (now=0;a[now].nxt!=-1&&pos>a[now].len;now=a[now].nxt) pos-=a[now].len; } //将新快赋值 void fillnode(int pos,int n,char data[],int nxt) { a[pos].nxt=nxt; a[pos].len=n; memcpy(a[pos].data,data,n); } //将块pos在p位置前后分开,变成两个块 void split(int pos,int p) { if (a[pos].len==p) return; int t=newnode(); fillnode(t,a[pos].len-p,a[pos].data+p,a[pos].nxt); a[pos].nxt=t; a[pos].len=p; } //把碎块合并 void maintain(int pos) { int t; for (;pos!=-1;pos=a[pos].nxt) for (t=a[pos].nxt;t!=-1&&a[pos].len+a[t].len<blocksize;t=a[t].nxt) { memcpy(a[pos].data+a[pos].len,a[t].data,a[t].len); a[pos].len+=a[t].len; a[pos].nxt=a[t].nxt; delnode(t); } } //在光标pos处插入长度为n的str void insert(int pos,int n) { int now,i,t; //now表示光标所在的块,pos表示光标在这个块中的位置 find(pos,now); split(now,pos); for (i=0;i+blocksize<=n;i+=blocksize) { t=newnode(); fillnode(t,blocksize,str+i,a[now].nxt); a[now].nxt=t; now=t; } if (i<n) { t=newnode(); fillnode(t,n-i,str+i,a[now].nxt); a[now].nxt=t; } maintain(now); } //从光标pos开始删除长度为n的字符串 void del(int pos,int n) { int i,now,t; //now表示光标所在的块,pos表示光标在这个块中的位置 find(pos,now); split(now,pos); //找到删除的末尾的点所处的块 for (i=a[now].nxt;i!=-1&&n>a[i].len;i=a[i].nxt) n-=a[i].len; split(i,n); i=a[i].nxt; for (t=a[now].nxt;t!=i;t=a[now].nxt) a[now].nxt=a[t].nxt,delnode(t); maintain(now); } //从pos这个位置开始输出长度为n的字符串 void get(int pos,int n) { int i,now,t; find(pos,now); i=min(n,a[now].len-pos); memcpy(str,a[now].data+pos,i); for (t=a[now].nxt;t!=-1&&i+a[t].len<=n;t=a[t].nxt) { memcpy(str+i,a[t].data,a[t].len); i+=a[t].len; } if (i<n&&t!=-1) memcpy(str+i,a[t].data,n-i); str =0; } int main() { init(); scanf("%d",&T); while (T--) { scanf("%s",opt); if (opt[0]=='M') scanf("%d",&cur);//改变光标的位置 if (opt[0]=='I')//插入一段区间 { scanf("%d",&_); read(_); insert(cur,_); } if (opt[0]=='P') cur--;//光标左移 if (opt[0]=='N') cur++;//光标右移 if (opt[0]=='D')//删除一段区间 { scanf("%d",&_); del(cur,_); } if (opt[0]=='G')//输出一段区间 { scanf("%d",&_); get(cur,_); puts(str); } } }
相关文章推荐
- BZOJ 1507([NOI2003]Editor-块状链表)
- bzoj 1507: [NOI2003]Editor (块状链表)
- bzoj1507 [NOI2003]Editor(块状链表)
- 1507: [NOI2003]Editor(块状链表)
- 【splay】BZOJ 1507:[NOI2003]Editor
- bzoj 1507: [NOI2003]Editor
- [BZOJ1507][NOI2003]Editor
- 洛谷.4008.[NOI2003]editor文本编辑器(块状链表)
- BZOJ 1507 [NOI2003]Editor
- 【BZOJ】1507: [NOI2003]Editor(Splay)
- BZOJ1507 [NOI2003]Editor 【splay】
- bzoj1507: [NOI2003]Editor
- 块状链表(附NOI 2003 Editor,POJ 2131 Key Insertion)
- BZOJ1507 [NOI2003]Editor 【splay】
- BZOJ1507 [NOI2003]Editor
- 【bzoj1507】[NOI2003]Editor /【bzoj1269】[AHOI2006]文本编辑器editor Splay
- BZOJ 1507 Editor(块状链表)
- BZOJ 1507 [NOI2003]Editor
- 【bzoj1507】[NOI2003]Editor
- 【BZOJ-1507】Editor 块状链表