P4008 [NOI2003] 文本编辑器
动态插入字符,动态删除字符,输出一个区间的字符串。
很明显可以直接用平衡树维护,当然也可以分块。
平衡树可以用 FHQTreap或者Splay ,这里用的是前者。
每次操作都可以看成分裂然后合并即可。
代码:
#include <bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
x=0;char ch=getchar();bool f=false;
while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=f?-x:x;
return ;
}
template <typename T>
inline void write(T x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10^48);
return ;
}
const int N=2e6+5;
int root,Cur;
int sta[N],top;
struct FHQTreap{
int siz,key,ls,rs;
char v;
#define v(x) t[x].v
#define siz(x) t[x].siz
#define key(x) t[x].key
#define ls(x) t[x].ls
#define rs(x) t[x].rs
}t[N];
inline int NewNode(){return top?sta[top--]:++Cur;}
inline void Pushup(int x){
siz(x)=siz(ls(x))+siz(rs(x))+1;
return ;
}
void Split(int now,int &x,int &y,int k){
if(!now) return x=y=0,void();
if(siz(ls(now))>=k) y=now,Split(ls(now),x,ls(y),k),Pushup(y);
else x=now,Split(rs(now),rs(x),y,k-siz(ls(now))-1),Pushup(x);
return ;
}
int Merge(int x,int y){
if(!x||!y) return x+y;
if(key(x)<=key(y)) return rs(x)=Merge(rs(x),y),Pushup(x),x;
else return ls(y)=Merge(x,ls(y)),Pushup(y),y;
}
char str[N];
int Build(int l,int r){
if(l>r) return 0;
int mid=l+r>>1,cur=NewNode();key(cur)=rand();
siz(cur)=1,v(cur)=str[mid];
ls(cur)=Build(l,mid-1),rs(cur)=Build(mid+1,r);
Pushup(cur);
return cur;
}
inline void Del(int x){ls(x)=rs(x)=siz(x)=0;sta[++top]=x;return ;}
void Delete(int x){
if(ls(x)) Delete(ls(x));
Del(x);
if(rs(x)) Delete(rs(x));
return ;
}
void Print(int x){
if(ls(x)) Print(ls(x));
putchar(v(x));
if(rs(x)) Print(rs(x));
return ;
}
int n;
int main(){
read(n);int now=0;
for(int i=1;i<=n;i++){
char op[25];int k,x,y,z;
scanf("%s",op);
if(op[0]=='M') read(now);
else if(op[0]=='I'){
read(k);int tot=0;
while(1){
char ch=getchar();
while(ch>126||ch<32||ch=='\n') ch=getchar();
str[++tot]=ch;
if(tot==k) break;
}
char ch=getchar();
Split(root,x,y,now);
root=Merge(x,Merge(Build(1,k),y));
}
else if(op[0]=='D'){
read(k);int w;
Split(root,x,w,now);Split(w,y,z,k);
Delete(y);
root=Merge(x,z);
}
else if(op[0]=='G'){
read(k);
Split(root,x,y,now);Split(y,y,z,k);
Print(y);putchar('\n');
root=Merge(x,Merge(y,z));
}
else if(op[0]=='P') now--;
else if(op[0]=='N') now++;
}
return 0;
}