看了看块状链表,就是数组和链表的合体。
看上去好高大尚,思想也很简单。
但是发现代码量也不是很小,而且代码理解起来也是费尽得很,倒不如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 }