博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[AHOI2006]文本编辑器 Splay tree区间操作
阅读量:5280 次
发布时间:2019-06-14

本文共 6439 字,大约阅读时间需要 21 分钟。

  题目链接:

  

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 
3 #include
4 #include
5 //#include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include
14 #include
15 #include
16 #include
17 #include
18 #include
19 #include
20 #include
21 #include
22 #include
23 using namespace std; 24 //using namespace __gnu_cxx; 25 //define 26 #define pii pair
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
T gcd(T a,T b){ return b?gcd(b,a%b):a;} 47 template
T lcm(T a,T b){ return a/gcd(a,b)*b;} 48 template
inline T lcm(T a,T b,T d){ return a/d*b;} 49 template
inline T Min(T a,T b){ return a
inline T Max(T a,T b){ return a>b?a:b;} 51 template
inline T Min(T a,T b,T c){ return min(min(a, b),c);} 52 template
inline T Max(T a,T b,T c){ return max(max(a, b),c);} 53 template
inline T Min(T a,T b,T c,T d){ return min(min(a, b),min(c,d));} 54 template
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\n",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\n",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的子树调整为goal118 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\n",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 }

 

 

转载于:https://www.cnblogs.com/zhsl/p/3223057.html

你可能感兴趣的文章
Java大数——a^b + b^a
查看>>
简单的数据库操作
查看>>
帧的最小长度 CSMA/CD
查看>>
普通求素数和线性筛素数
查看>>
PHP截取中英文混合字符
查看>>
电子眼抓拍大解密
查看>>
51nod1076 (边双连通)
查看>>
Linux pipe函数
查看>>
Zerver是一个C#开发的Nginx+PHP+Mysql+memcached+redis绿色集成开发环境
查看>>
程序的静态链接,动态链接和装载 (补充)
查看>>
关于本博客说明
查看>>
[Kaggle] Sentiment Analysis on Movie Reviews
查看>>
价值观
查看>>
mongodb命令----批量更改文档字段名
查看>>
国外常见互联网盈利创新模式
查看>>
android:scaleType属性
查看>>
shell脚本
查看>>
Upload Image to .NET Core 2.1 API
查看>>
【雷电】源代码分析(二)-- 进入游戏攻击
查看>>
Linux中防火墙centos
查看>>