[NOI2003]Editor(块状链表)

传送门

看了看块状链表,就是数组和链表的合体。

看上去好高大尚,思想也很简单。

但是发现代码量也不是很小,而且代码理解起来也是费尽得很,倒不如splay用起来顺手。

在加上适用范围貌似不是特别广,所以只把模板贴在这,只当了解思想,暂时先不使用。(也不会用啊)

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<queue>
  5 using namespace std;
  6 
  7 const int N=1<<25;
  8 const int blocksize=20000;
  9 const int blocknum=N/blocksize*3;
 10 
 11 int T,_;
 12 int cur;
 13 char str[5000005],opt[100];
 14 queue <int> q;
 15 struct node
 16 {
 17     char data[blocksize+111];
 18     int len,nxt;
 19 }a[blocknum+1000];
 20 
 21 void init()
 22 {
 23     for (int i=1;i<=blocknum;++i) q.push(i);
 24     a[0].len=0; a[0].nxt=-1;
 25 }
 26 void read(int len)
 27 {
 28     int i=-1;
 29     while (i<len-1)
 30     {
 31         i++;
 32         char c=getchar();
 33         str[i]=c;
 34         if (c<32||c>126) i--;
 35     }
 36 }
 37 //新开一个块的节点 
 38 int newnode()
 39 {
 40     int temp=q.front(); q.pop();
 41     return temp;
 42 }
 43 //回收块的节点 
 44 void delnode(int t)
 45 {
 46     q.push(t);
 47 }
 48 //找到pos所在的块,并使pos表示在当前块中的位置 
 49 void find(int &pos,int &now)
 50 {
 51     for (now=0;a[now].nxt!=-1&&pos>a[now].len;now=a[now].nxt)
 52         pos-=a[now].len;
 53 }
 54 //将新快赋值 
 55 void fillnode(int pos,int n,char data[],int nxt)
 56 {
 57     a[pos].nxt=nxt; a[pos].len=n;
 58     memcpy(a[pos].data,data,n);
 59 }
 60 //将块pos在p位置前后分开,变成两个块 
 61 void split(int pos,int p)
 62 {
 63     if (a[pos].len==p) return;
 64     int t=newnode();
 65     fillnode(t,a[pos].len-p,a[pos].data+p,a[pos].nxt);
 66     a[pos].nxt=t; a[pos].len=p;
 67 }
 68 //把碎块合并 
 69 void maintain(int pos)
 70 {
 71     int t;
 72     for (;pos!=-1;pos=a[pos].nxt)
 73         for (t=a[pos].nxt;t!=-1&&a[pos].len+a[t].len<blocksize;t=a[t].nxt)
 74         {
 75             memcpy(a[pos].data+a[pos].len,a[t].data,a[t].len);
 76             a[pos].len+=a[t].len; a[pos].nxt=a[t].nxt; delnode(t);
 77         }
 78 }
 79 //在光标pos处插入长度为n的str 
 80 void insert(int pos,int n)
 81 {
 82     int now,i,t;
 83     //now表示光标所在的块,pos表示光标在这个块中的位置 
 84     find(pos,now);
 85     split(now,pos);
 86     for (i=0;i+blocksize<=n;i+=blocksize)
 87     {
 88         t=newnode();
 89         fillnode(t,blocksize,str+i,a[now].nxt);
 90         a[now].nxt=t;
 91         now=t;
 92     }
 93     if (i<n)
 94     {
 95         t=newnode();
 96         fillnode(t,n-i,str+i,a[now].nxt);
 97         a[now].nxt=t;
 98     }
 99     maintain(now);
100 }
101 //从光标pos开始删除长度为n的字符串 
102 void del(int pos,int n)
103 {
104     int i,now,t;
105     //now表示光标所在的块,pos表示光标在这个块中的位置 
106     find(pos,now);
107     split(now,pos);
108     //找到删除的末尾的点所处的块 
109     for (i=a[now].nxt;i!=-1&&n>a[i].len;i=a[i].nxt)
110         n-=a[i].len;
111     split(i,n); i=a[i].nxt;
112     for (t=a[now].nxt;t!=i;t=a[now].nxt)
113         a[now].nxt=a[t].nxt,delnode(t);
114     maintain(now);
115 }
116 //从pos这个位置开始输出长度为n的字符串 
117 void get(int pos,int n)
118 {
119     int i,now,t;
120     find(pos,now);
121     i=min(n,a[now].len-pos);
122     memcpy(str,a[now].data+pos,i);
123     for (t=a[now].nxt;t!=-1&&i+a[t].len<=n;t=a[t].nxt)
124     {
125         memcpy(str+i,a[t].data,a[t].len);
126         i+=a[t].len;
127     }
128     if (i<n&&t!=-1) memcpy(str+i,a[t].data,n-i);
129     str[n]=0;
130 }
131 int main()
132 {
133     init();
134     scanf("%d",&T);
135     while (T--)
136     {
137         scanf("%s",opt);
138         if (opt[0]=='M') scanf("%d",&cur);//改变光标的位置 
139         if (opt[0]=='I')//插入一段区间 
140         {
141             scanf("%d",&_);
142             read(_);
143             insert(cur,_);
144         }
145         if (opt[0]=='P') cur--;//光标左移 
146         if (opt[0]=='N') cur++;//光标右移 
147         if (opt[0]=='D')//删除一段区间 
148         {
149             scanf("%d",&_);
150             del(cur,_);
151         }
152         if (opt[0]=='G')//输出一段区间 
153         {
154             scanf("%d",&_);
155             get(cur,_);
156             puts(str);
157         }
158     }
159 }
View Code
原文地址:https://www.cnblogs.com/zhenghaotian/p/6747314.html