【BZOJ】1507: [NOI2003]Editor(Splay)

http://www.lydsy.com/JudgeOnline/problem.php?id=1507

当练splay模板了,发现wjmzbmr的splay写得异常简介,学习了。orzzzzzzzzzzz!!!!!!

这个版本很好写的,比数组的好写多了。但是异常的慢啊T_T

这个版本的splay,会修改null的fa,但不影响结果,这点要记住。

#include <string>
#include <cstdio>

using namespace std;
char strI[1024*1024+100];

struct Splay {
	struct node{
		node *ch[2], *fa;
		char key;
		int size;
		node() { ch[0]=ch[1]=fa=NULL; size=key=0; }
		void pushup() { size=ch[0]->size+ch[1]->size+1; }
		bool d() { return this==fa->ch[1]; }
		void setc(node *c, int _d) {
			ch[_d]=c; c->fa=this;
		}
	}*null, *root;
	Splay() {
		null=new node;
		root=null;
		root=newnode(0);
		node *t=newnode(0);
		root->setc(t, 1);
		root->pushup();
	}
	node* newnode(char key) {
		node *ret=new node;
		ret->ch[0]=ret->ch[1]=ret->fa=null;
		ret->key=key; ret->size=1;
		return ret;
	}
	void rot(node *r) {
		node *fa=r->fa; bool d=r->d();
		fa->fa->setc(r, fa->d());
		fa->setc(r->ch[!d], d);
		r->setc(fa, !d);
		fa->pushup();
		if(fa==root) root=r;
	}
	void splay(node *r, node *fa) {
		while(r->fa!=fa) {
			if(r->fa->fa==fa) rot(r);
			else r->d()==r->fa->d()?(rot(r->fa), rot(r)):(rot(r), rot(r));
		}
		r->pushup();
	}
	node* sel(int k) {
		int s;
		for(node *t=root; ;) {
			s=t->ch[0]->size;
			if(s==k) return t;
			t=t->ch[k>s];
			if(k>s) k-=s+1;
		}
	}
	node* getrange(int l, int r) {
		node *left=sel(l); splay(left, null);
		node *right=sel(r); splay(right, left);
		return right;
	}
	void insert(int at, int cur) {
		node *t=getrange(at, at+1);
		t->setc(build(0, cur), 0); t->pushup();
		splay(t, null);
	}
	void remove(int at, int n) {
		node *t=getrange(at, at+n+1);
		t->setc(null, 0); t->pushup();
		splay(t, null);
	}
	node* build(int l, int r) {
		if(l>=r) return null;
		int m=(l+r)>>1;
		node *t=newnode(strI[m]);
		t->setc(build(l, m), 0);
		t->setc(build(m+1, r), 1);
		t->pushup();
		return t;
	}
	void print(node *r) {
		if(r==null) return;
		print(r->ch[0]);
		printf("%c", r->key);
		print(r->ch[1]);
	}
	void print(int at, int n) {
		node *t=getrange(at, at+n+1);
		print(t->ch[0]);
		printf("
");
	}
}splay;

char s[10];

int main() {
	int n, t, cur, at=0;
	scanf("%d", &n);
	while(n--) {
		scanf("%s", s);
		if(s[0]=='I') {
			scanf("%d", &t);
			cur=0;
			while(t--) {
				while(strI[cur]=getchar(), strI[cur]=='
');
				cur++;
			}
			splay.insert(at, cur);
		}
		else if(s[0]=='M') {
			scanf("%d", &at);
		}
		else if(s[0]=='D') {
			scanf("%d", &t);
			splay.remove(at, t);
		}
		else if(s[0]=='G') {
			scanf("%d", &t);
			splay.print(at, t);
		}
		else if(s[0]=='P') --at;
		else if(s[0]=='N') ++at;
	}
	return 0;
}

Description

Input

输入文件editor.in的第一行是指令条数t,以下是需要执行的t个操作。其中: 为了使输入文件便于阅读,Insert操作的字符串中可能会插入一些回车符,请忽略掉它们(如果难以理解这句话,可以参考样例)。 除了回车符之外,输入文件的所有字符的ASCII码都在闭区间[32, 126]内。且行尾没有空格。 这里我们有如下假定:  MOVE操作不超过50000个,INSERT和DELETE操作的总个数不超过4000,PREV和NEXT操作的总个数不超过200000。  所有INSERT插入的字符数之和不超过2M(1M=1024*1024),正确的输出文件长度不超过3M字节。  DELETE操作和GET操作执行时光标后必然有足够的字符。MOVE、PREV、NEXT操作必然不会试图把光标移动到非法位置。  输入文件没有错误。 对C++选手的提示:经测试,最大的测试数据使用fstream进行输入有可能会比使用stdio慢约1秒。

Output

输出文件editor.out的每行依次对应输入文件中每条GET指令的输出。

Sample Input

15
Insert 26
abcdefghijklmnop
qrstuv wxy
Move 16
Delete 11
Move 5
Insert 1
^
Next
Insert 1
_
Next
Next
Insert 4
./.
Get 4
Prev
Insert 1
^
Move 0
Get 22

Sample Output

./.
abcde^_^f./.ghijklmno

HINT

Source

原文地址:https://www.cnblogs.com/iwtwiioi/p/3866705.html