• [AHOI2006]文本编辑器 Splay tree区间操作


      题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1269

      

    Description

    这些日子,可可不和卡卡一起玩了,原来可可正废寝忘食的想做一个简单而高效的文本编辑器。你能帮助他吗?为了明确任务目标,可可对“文本编辑器”做了一个抽象的定义: 

    文本:由0个或多个字符构成的序列。这些字符的ASCII码在闭区间[32, 126]内,也就是说,这些字符均为可见字符或空格。光标:在一段文本中用于指示位置的标记,可以位于文本的第一个字符之前,文本的最后一个字符之后或文本的某两个相邻字符之间。文本编辑器:为一个可以对一段文本和该文本中的一个光标进行如下七条操作的程序。如果这段文本为空,我们就说这个文本编辑器是空的。 编写一个程序: 建立一个空的文本编辑器。 从输入文件中读入一些操作指令并执行。 对所有执行过的GET操作,将指定的内容写入输出文件。

    Input

    输入文件中第一行是指令条数N,以下是需要执行的N个操作。除了回车符之外,输入文件的所有字符的ASCII码都在闭区间[32, 126]内。且行尾没有空格。

    Output

    依次对应输入文件中每条GET指令的输出,不得有任何多余的字符。

    Sample Input

    10
    Insert 13
    Balanced eert
    Move 2
    Delete 5
    Next
    Insert 7
    editor
    Move 0
    Get
    Move 11
    Rotate 4
    Get

    Sample Output

    B
    t

    HINT

    对输入数据我们有如下假定: MOVE操作不超过50 000个,INSERT、DELETE和ROTATE操作作的总个数不超过6 000,GET操作不超过20 000个,PREV和NEXT操作的总个数不超过20 000。 所有INSERT插入的字符数之和不超过2M(1M=1 024*1 024)。 DELETE操作、ROTATE操作和GET操作执行时光标后必然有足够的字符。MOVE、PREV、NEXT操作不会把光标移动到非法位置。 输入文件没有错误。

      用个全局变量记录cursor的位置,对于每个操作:

        Insert:先旋转,然后插入区间到根的右儿子的左子树。

        Delete:先旋转,然后删除根的右儿子的左子树。

        Rotate:区间标记,懒惰更新。

        Get:直接输出光标的后一个字符。

        其它的直接修改cursor的位置。。。

      1 //STATUS:C++_AC_1296MS_48380KB
      2 #include <functional>
      3 #include <algorithm>
      4 #include <iostream>
      5 //#include <ext/rope>
      6 #include <fstream>
      7 #include <sstream>
      8 #include <iomanip>
      9 #include <numeric>
     10 #include <cstring>
     11 #include <cassert>
     12 #include <cstdio>
     13 #include <string>
     14 #include <vector>
     15 #include <bitset>
     16 #include <queue>
     17 #include <stack>
     18 #include <cmath>
     19 #include <ctime>
     20 #include <list>
     21 #include <set>
     22 #include <map>
     23 using namespace std;
     24 //using namespace __gnu_cxx;
     25 //define
     26 #define pii pair<int,int>
     27 #define mem(a,b) memset(a,b,sizeof(a))
     28 #define lson l,mid,rt<<1
     29 #define rson mid+1,r,rt<<1|1
     30 #define PI acos(-1.0)
     31 //typedef
     32 //typedef __int64 LL;
     33 //typedef unsigned __int64 ULL;
     34 //const
     35 const int N=1024*1024*2+10;
     36 const int INF=0x3f3f3f3f;
     37 const int MOD=100000,STA=8000010;
     38 //const LL LNF=1LL<<60;
     39 const double EPS=1e-8;
     40 const double OO=1e15;
     41 const int dx[4]={-1,0,1,0};
     42 const int dy[4]={0,1,0,-1};
     43 const int day[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
     44 //Daily Use ...
     45 inline int sign(double x){return (x>EPS)-(x<-EPS);}
     46 template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;}
     47 template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
     48 template<class T> inline T lcm(T a,T b,T d){return a/d*b;}
     49 template<class T> inline T Min(T a,T b){return a<b?a:b;}
     50 template<class T> inline T Max(T a,T b){return a>b?a:b;}
     51 template<class T> inline T Min(T a,T b,T c){return min(min(a, b),c);}
     52 template<class T> inline T Max(T a,T b,T c){return max(max(a, b),c);}
     53 template<class T> inline T Min(T a,T b,T c,T d){return min(min(a, b),min(c,d));}
     54 template<class T> inline T Max(T a,T b,T c,T d){return max(max(a, b),max(c,d));}
     55 //End
     56 
     57 #define Key_value ch[ch[root][1]][0]
     58 int pre[N],ch[N][2];  //分别表示父结点,键值,左右孩子(0为左孩子,1为右孩子),根结点,结点数量
     59 int sz[N],st[N];   //子树规模,内存池
     60 int root,tot,top;   //根节点,根节点数量,内存池容量
     61 //题目特定数目
     62 char key[N],s[N];
     63 bool rev[N];
     64 int n,m,cursor;
     65 //debug部分copy from hh
     66 void Treaval(int x) {
     67     if(x) {
     68         Treaval(ch[x][0]);
     69         printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d rev = %2d key = %2c
    ",x,ch[x][0],ch[x][1],pre[x],sz[x],rev[x],key[x]);
     70         Treaval(ch[x][1]);
     71     }
     72 }
     73 void debug() {printf("%d
    ",root);Treaval(root);}
     74 //以上Debug
     75 //新建一个结点
     76 void NewNode(int &x,int fa,char c)
     77 {
     78     if(top)x=st[--top];
     79     else x=++tot;
     80     key[x]=c;
     81     pre[x]=fa;
     82     sz[x]=1;
     83     rev[x]=0;
     84     ch[x][0]=ch[x][1]=0;  //左右孩子为空
     85 }
     86 
     87 void Push_Up(int x)
     88 {
     89     sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;
     90 }
     91 
     92 void Push_Down(int x)
     93 {
     94     if(rev[x]){
     95         rev[ch[x][0]]^=1;
     96         rev[ch[x][1]]^=1;
     97         swap(ch[x][0],ch[x][1]);
     98         rev[x]=0;
     99     }
    100 }
    101 //旋转,kind为1为右旋,kind为0为左旋
    102 void Rotate(int x,int kind)
    103 {
    104     int y=pre[x],z=pre[y];
    105     Push_Down(y);
    106     Push_Down(x);  //先把y的标记向下传递,再把x的标记往下传递
    107     //类似SBT,要把其中一个分支先给父节点
    108     ch[y][!kind]=ch[x][kind];
    109     pre[ch[x][kind]]=y;
    110     //如果父节点不是根结点,则要和父节点的父节点连接起来
    111     if(z)ch[z][ch[z][1]==y]=x;
    112     pre[x]=z;
    113     ch[x][kind]=y;
    114     pre[y]=x;
    115     Push_Up(y);  //维护y结点,不要维护x节点,x节点会再次Push_Down,最后维护一下x节点即可
    116 }
    117 //Splay调整,将根为r的子树调整为goal
    118 void Splay(int x,int goal)
    119 {
    120     int y,z,kind;
    121     while(pre[x]!=goal){
    122         //父节点即是目标位置,goal为0表示,父节点就是根结点
    123         y=pre[x];
    124         Push_Down(pre[y]);Push_Down(y);Push_Down(x);   //设计到反转操作,要先更新,然后在判断!!
    125         if(pre[y]==goal){
    126             Rotate(x,ch[y][0]==x);
    127         }
    128         else {
    129             kind=ch[pre[y]][0]==y;
    130             //两个方向不同,则先左旋再右旋
    131             if(ch[y][kind]==x){
    132                 Rotate(x,!kind);
    133                 Rotate(x,kind);
    134             }
    135             //两个方向相同,相同方向连续两次
    136             else {
    137                 Rotate(y,kind);
    138                 Rotate(x,kind);
    139             }
    140         }
    141     }
    142     //更新根结点
    143     Push_Up(x);
    144     if(goal==0)root=x;
    145 }
    146 
    147 void RotateTo(int k,int goal)
    148 {
    149     int x=root;
    150     Push_Down(x);
    151     while(sz[ch[x][0]]!=k){
    152         if(sz[ch[x][0]]>k)
    153             x=ch[x][0];
    154         else {
    155             k-=sz[ch[x][0]]+1;
    156             x=ch[x][1];
    157         }
    158         Push_Down(x);
    159     }
    160     Splay(x,goal);
    161 }
    162 //建树,中间结点先建立,然后分别对区间两端在左右子树建立
    163 void BuildTree(int &x,int l,int r,int fa)
    164 {
    165     if(l>r)return;
    166     int mid=(l+r)>>1;
    167     NewNode(x,fa,s[mid]);
    168     BuildTree(ch[x][0],l,mid-1,x);
    169     BuildTree(ch[x][1],mid+1,r,x);
    170     Push_Up(x);
    171 }
    172 
    173 void Init()
    174 {
    175     root=top=tot=0;
    176     ch[0][0]=ch[0][1]=sz[0]=pre[0]=rev[0]=key[0]=0;
    177 
    178     NewNode(root,0,0);
    179     NewNode(ch[root][1],root,0);
    180     cursor=0;
    181 }
    182 
    183 void Insert(int len)
    184 {
    185     RotateTo(cursor,0);
    186     RotateTo(cursor+1,root);
    187     BuildTree(Key_value,0,len-1,ch[root][1]);
    188     Push_Up(ch[root][1]);
    189     Push_Up(root);
    190 }
    191 
    192 void Delete(int n)
    193 {
    194     RotateTo(cursor,0);
    195     RotateTo(cursor+n+1,root);
    196     Key_value=0;
    197     Push_Up(ch[root][1]);
    198     Push_Up(root);
    199 }
    200 
    201 void Rotate(int n)
    202 {
    203     RotateTo(cursor,0);
    204     RotateTo(cursor+n+1,root);
    205     rev[Key_value]^=1;
    206 }
    207 
    208 void Get()
    209 {
    210     int x=root,k=cursor+1;
    211     Push_Down(x);
    212     while(sz[ch[x][0]]!=k){
    213         if(sz[ch[x][0]]>k)
    214             x=ch[x][0];
    215         else {
    216             k-=sz[ch[x][0]]+1;
    217             x=ch[x][1];
    218         }
    219         Push_Down(x);
    220     }
    221     printf("%c
    ",key[x]);
    222 }
    223 
    224 int main()
    225 {
    226  //   freopen("in.txt","r",stdin);
    227     int i,j,k;
    228     char op[15];
    229     while(~scanf("%d",&n))
    230     {
    231         Init();
    232         while(n--){
    233             scanf("%s",op);
    234             if(op[0]=='M'){
    235                 scanf("%d",&k);
    236                 cursor=k?k:0;
    237             }
    238             else if(op[0]=='I'){
    239                 scanf("%d",&k);
    240                 getchar();
    241                 gets(s);
    242                 Insert(k);
    243             }
    244             else if(op[0]=='D'){
    245                 scanf("%d",&k);
    246                 Delete(k);
    247             }
    248             else if(op[0]=='R'){
    249                 scanf("%d",&k);
    250                 Rotate(k);
    251             }
    252             else if(op[0]=='G'){
    253                 Get();
    254             }
    255             else if(op[0]=='P'){
    256                 cursor--;
    257             }
    258             else {
    259                 cursor++;
    260             }
    261         }
    262     }
    263     return 0;
    264 }

     

  • 相关阅读:
    文件路径总结
    git本地仓库关联远程仓库
    webpack-dev-server版本
    box-sizing重置
    事件委托优缺点和实现
    移动端经验总结(持续更新)
    点击其他区域关闭dialog
    css3图片变灰
    安装 ubuntu 后,使用 sed 更换国内源
    在virtualBox中打开vdi(转载)
  • 原文地址:https://www.cnblogs.com/zhsl/p/3223057.html
Copyright © 2020-2023  润新知