• [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
  • 相关阅读:
    341. Flatten Nested List Iterator
    667. Beautiful Arrangement II
    953. Verifying an Alien Dictionary
    1704. Determine if String Halves Are Alike
    MySQL数据库的数据类型详解【转】
    Dart之数组(List)的相关方法总结【转】
    Flutter解决点击非输入框时关闭键盘问题及TextFormField焦点切换问题【转】
    Flutter Switch开关【转】
    Image Picker
    Flutter按钮添加背景图片及文字【转】
  • 原文地址:https://www.cnblogs.com/zhenghaotian/p/6747314.html
Copyright © 2020-2023  润新知