fhq的 挖掘treap的潜力

http://fanhq666.blog.163.com/blog/static/819434262011021105212299/
你的Treap能支持以下操作吗?1.区间增减
2.区间求最小
3.区间反转(倒序)
4.区间移动(把一段剪切、粘贴)
不能?只能用splay?


其实,Treap也可以办到。
方法就是:设计把一个子树split成两个子树的算法,以及把两个子树merge的算法。


例:poj3580,代码见最后


另外一个应用:可持久化Treap
设计一个数据结构维护一个序列
 插入一个元素
 删除一个元素
 移动连续的一段(就是剪切、粘贴)
 *查询m次操作之前的第p个元素是谁
例:超级文本编辑器(我正在构思的一道题)
文本长度不超过100000
每次可以插入、删除、剪切粘贴
要求在线算法
每个操作10微秒时限,一共32M内存


这个可以参见算法导论,核心思想是:一个节点创建之后就不再删除。另外用垃圾回收。
poj3580
#include <cstdio>
#include <algorithm>
using namespace std;
int ran(){
	static int x=1364684679;
	x+=(x<<2)+1;
	return x;
}
struct node{
	int k,mn,delta,mark,w,sz;
	node *l,*r;
	static node* getnew(node *w=NULL){
		static node *list=NULL;
		if (w){
			w->r=list;list=w;
			return NULL;
		}
		if (!list){
			node *q=new node[10000];
			for (int i=0;i<10000;i++){
				q[i].w=ran();
				q[i].r=list;list=q+i;
			}
		}
		node *p=list;list=list->r;
		p->l=p->r=NULL;p->delta=p->mark=0;
		return p;
	}
	void down(){
		if (mark){
			if (l)swap(l->l,l->r),l->mark^=1;
			if (r)swap(r->l,r->r),r->mark^=1;
			mark=0;
		}
		if (delta){
			if (l)l->mn+=delta,l->delta+=delta,l->k+=delta;
			if (r)r->mn+=delta,r->delta+=delta,r->k+=delta;
			delta=0;
		}
	}
	void update(){
		mn=k;
		if (l && mn>l->mn+delta)mn=l->mn+delta;
		if (r && mn>r->mn+delta)mn=r->mn+delta;
		sz=1;
		if (l)sz+=l->sz;
		if (r)sz+=r->sz;
	}
};
#define SIZE(_) ((_)?(_)->sz:0)
struct Treap{
	node *root;
	Treap(){root=NULL;}
	void ins(node *&p,int a,int k){
		if (!p){
			p=node::getnew();
			p->k=p->mn=k;p->sz=1;
		}else{
			p->down();
			if (SIZE(p->l)>=a){
				ins(p->l,a,k);
				node *q=p->l;
				if (q->w<p->w){
					q->down();
					p->l=q->r;q->r=p;p=q;
					p->r->update();
				}
			}else{
				ins(p->r,a-SIZE(p->l)-1,k);
				node *q=p->r;
				if (q->w<p->w){
					q->down();
					p->r=q->l;q->l=p;p=q;
					p->l->update();
				}
			}
			p->update();
		}
	}
	void ins(int a,int k){ins(root,a,k);}
	static void merge(node *&p,node *x,node *y){
		if (!x || !y){
			p=x?x:y;
		}else if (x->w<y->w){
			x->down();
			merge(x->r,x->r,y);
			x->update();
			p=x;
		}else{
			y->down();
			merge(y->l,x,y->l);
			y->update();
			p=y;
		}
	}
	void del(node *&p,int a){
		p->down();
		if (SIZE(p->l)==a){
			node *q=p;
			merge(p,p->l,p->r);
			node::getnew(q);
		}else if (SIZE(p->l)>a){
			del(p->l,a);
			p->update();
		}else{
			del(p->r,a-SIZE(p->l)-1);
			p->update();
		}
	}
	void del(int a){del(root,a);}
	static void cut(node *p,node *&x,node *&y,int a){
		if (a==0){
			x=NULL;y=p;
		}else if (a==SIZE(p)){
			x=p;y=NULL;
		}else{
			p->down();
			if (SIZE(p->l)>=a){
				y=p;
				cut(p->l,x,y->l,a);
				y->update();
			}else{
				x=p;
				cut(p->r,x->r,y,a-SIZE(p->l)-1);
				x->update();
			}
		}
	}
	int ask(node *p,int a,int b){
		if (a==0 && b==SIZE(p)-1)return p->mn;
		p->down();
		int u=SIZE(p->l);
		int r=(a<=u && u<=b?p->k:~0u>>1);
		if (a<u)r=min(r,ask(p->l,a,b>=u?u-1:b));
		if (b>u)r=min(r,ask(p->r,a<=u?0:a-u-1,b-u-1));
		return r;
	}
	int ask(int a,int b){return ask(root,a,b);}
	void dfs(node *p,int lv){
		if (p){
			dfs(p->l,lv+1);
			for (int i=0;i<lv;i++)putchar(' '),putchar(' ');
			printf("%d %d %d %d %d\n",p->k,p->sz,p->mn,p->delta,p->mark);
			dfs(p->r,lv+1);
		}
	}
	void dfs(){dfs(root,0);puts("");}
}T;
void Ins(int a,int k){
	//printf("ins %d %d\n",a,k);
	T.ins(a,k);
}
void Del(int a){
	//printf("del %d\n",a);
	T.del(a);
}
void Revolve(int a,int b,int c){
	//printf("revolve %d %d %d\n",a,b,c);
	node *p,*q,*r,*s;
	Treap::cut(T.root,p,q,a);
	Treap::cut(q,q,r,b-a+1);
	Treap::cut(r,r,s,c-b);
	Treap::merge(p,p,r);
	Treap::merge(p,p,q);
	Treap::merge(T.root,p,s);
}
void Reverse(int a,int b){
	//printf("reverse %d %d\n",a,b);
	node *p,*q,*r;
	Treap::cut(T.root,p,q,a);
	Treap::cut(q,q,r,b-a+1);
	q->mark^=1;swap(q->l,q->r);
	Treap::merge(p,p,q);
	Treap::merge(T.root,p,r);
}
void Add(int a,int b,int c){
	//printf("add %d %d %d\n",a,b,c);
	node *p,*q,*r;
	Treap::cut(T.root,p,q,a);
	Treap::cut(q,q,r,b-a+1);
	//T.dfs(q,0);puts("");
	q->k+=c;q->mn+=c;q->delta+=c;
	//printf("c=%d\n",c);
	//T.dfs(q,0);
	//puts("");
	Treap::merge(p,p,q);
	Treap::merge(T.root,p,r);
}
int Ask(int a,int b){
	//printf("ask %d %d\n",a,b);
	return T.ask(a,b);
}
int main()
{
	int N;
	scanf("%d",&N);
	for (int i=0;i<N;i++){
		int x;
		scanf("%d",&x);
		Ins(i,x);
	}
	int M;
	//T.dfs();
	scanf("%d",&M);
	char buf[100];
	while (M--){
		scanf("%s",buf);
		if (buf[0]=='A'){
			int x,y,d;
			scanf("%d%d%d",&x,&y,&d);x--;y--;
			Add(x,y,d);
			//T.dfs();
		}else if (buf[0]=='I'){
			int x,y;
			scanf("%d%d",&x,&y);
			Ins(x,y);
		}else if (buf[0]=='D'){
			int x;
			scanf("%d",&x);x--;
			Del(x);
		}else if (buf[0]=='M'){
			int x,y;
			scanf("%d%d",&x,&y);x--;y--;
			printf("%d\n",Ask(x,y));
		}else if (buf[3]=='E'){
			int x,y;
			scanf("%d%d",&x,&y);x--;y--;
			Reverse(x,y);
		}else{
			int x,y,t;
			scanf("%d%d%d",&x,&y,&t);x--;y--;
			t%=(y-x+1);
			t+=(y-x+1);
			t%=(y-x+1);
			if (t){
				Revolve(x,y-t,y);
			}
		}
	}
	return 0;
}


文本编辑器
#include <cstdio>
#include <bits/stl_pair.h>
#include <queue>
#include <deque>
#include <algorithm>
using namespace std;
int ran(){
	static int x=222313214;
	x+=(x<<2)+1;
	return x;
}
struct node{
	int w,sz;
	char k;
	node *l,*r;
	static node* getnew(node *p=NULL){
		static node * list=NULL;
		if (p){
			p->w=ran();
			p->r=list;list=p;
			return NULL;
		}
		if (!list){
			node *p=new node[10000];
			for (int i=0;i<10000;i++){
				p[i].r=list;list=p+i;
				p[i].w=ran();
			}
		}
		node *q=list;
		list=list->r;
		q->l=NULL;q->r=NULL;q->sz=1;
		return q;
	}
};
#define SIZE(_) ((_)?(_)->sz:0)
int M,curid;
queue<pair<int,node*> > Literbox;
deque<node*> Roots;
void giveback(node *p){
	Literbox.push(make_pair(curid,p));
}
void dfs(node *p,int a,int b){
	if (p){
		int u=SIZE(p->l);
		if (u>a)dfs(p->l,a,min(b,u-1));
		if (a<=u && u<=b)putchar(p->k);
		if (b>u)dfs(p->r,max(a-u-1,0),b-u-1);
	}
}
node * combine(node *p,node *q){
	if (!p || !q)return p?p:q;
	if (p->w<q->w){
		node *a=node::getnew();
		a->k=p->k;
		a->w=p->w;
		a->sz=p->sz+q->sz;
		a->l=p->l;
		a->r=combine(p->r,q);
		giveback(p);
		return a;
	}else{
		node *a=node::getnew();
		a->k=q->k;
		a->w=q->w;
		a->sz=p->sz+q->sz;
		a->r=q->r;
		a->l=combine(p,q->l);
		giveback(q);
		return a;
	}
}
void cutdown(node *p,node *&x,node *&y,int a){
	if (a==0)x=NULL,y=p;
	else if (a==SIZE(p)){
		x=p;y=NULL;
	}else{
		if (SIZE(p->l)+1<=a){
			x=node::getnew();
			x->k=p->k;x->w=p->w;
			x->sz=a;
			x->l=p->l;
			cutdown(p->r,x->r,y,a-SIZE(p->l)-1);
			giveback(p);
		}else{
			y=node::getnew();
			y->k=p->k;y->w=p->w;
			y->sz=p->sz-a;
			y->r=p->r;
			cutdown(p->l,x,y->l,a);
			giveback(p);
		}
	}
}
void treeadd(node *&p,node *q){
	if (!p){
		p=q;
	}else{
		if (p->w<q->w){
			treeadd(p->r,q);
			p->sz++;
		}else{
			q->l=p;q->sz=p->sz+1;
			p=q;
		}
	}
}
void Insert(int i,char a){
	node *p=node::getnew();
	p->k=a;
	node *x,*y;
	cutdown(Roots.back(),x,y,i);
	x=combine(x,p);x=combine(x,y);
	Roots.push_back(x);
	curid++;
}
void Delete(int i){
	node *x,*y,*z;
	cutdown(Roots.back(),x,y,i);
	cutdown(y,y,z,1);
	giveback(y);
	x=combine(x,z);
	Roots.push_back(x);
	curid++;
}
void Revolve(int a,int b,int c){
	node *p,*q,*r,*s;
	cutdown(Roots.back(),p,q,a);
	cutdown(q,q,r,b-a+1);
	cutdown(r,r,s,c-b);
	p=combine(p,r);
	p=combine(p,q);
	p=combine(p,s);
	Roots.push_back(p);
	curid++;
}
void Print(int a,int x,int y){
	node *p=Roots.at(Roots.size()-1-a);
	dfs(p,x,y);
	puts("");
}
void readstr(vector<char> &a){
	char c;
	while (c=getchar(),c==10 || c==13 || c==' ');
	while (c!=10 && c!=13){
		a.push_back(c);
		c=getchar();
	}
}
int main()
{
	scanf("%d",&M);
	vector<char> chs;
	readstr(chs);
	node *r=NULL;
	for (int i=0;i<(int)chs.size();i++){
		node *p=node::getnew();
		p->k=chs[i];
		treeadd(r,p);
	}
	Roots.push_back(r);
	curid=0;
	char cmd[10];
	while (scanf("%s",cmd)!=EOF){
		if (cmd[0]=='I'){
			int x;
			scanf("%d",&x);
			scanf("%s",cmd);
			Insert(x,cmd[0]);
		}else if (cmd[0]=='D'){
			int x;
			scanf("%d",&x);
			Delete(x-1);
		}else if (cmd[0]=='P'){
			int x,y,z;
			scanf("%d%d%d",&x,&y,&z);
			Print(x,y-1,z-1);
		}else if (cmd[0]=='C'){
			int x,y,z;
			scanf("%d%d%d",&x,&y,&z);
			Revolve(x-1,y-1,z-1);
		}
		while (!Literbox.empty() && Literbox.front().first<curid-M){
			node::getnew(Literbox.front().second);
			Literbox.pop();
		}
		while ((int)Roots.size()>M)Roots.pop_front();
	}
	return 0;
}




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可持久化splay是一种数据结构,它是对splay树进行修改和查询的一种扩展。在传统的splay树中,对树的修改操作会破坏原有的树结构,而可持久化splay树则允许我们对树进行修改、查询,并且可以保存修改后的每个版本的树结构。 在可持久化splay树中,我们不会直接对原树进行修改,而是通过复制每个节点来创建新的版本。这样,每个版本都可以独立地修改和查询,保留了原有版本的结构和状态。每个节点保存了其左子树和右子树的引用,使得可以在不破坏原有版本的情况下进行修改和查询。 为了实现可持久化splay树,我们可以使用一些技巧,比如引用中提到的哨兵节点和假的父节点和孩子节点。这些技巧可以帮助我们处理根节点的旋转和其他操作。 此外,可持久化splay树还可以与其他数据结构相结合,比如引用中提到的可持久化线段树。这种结合可以帮助我们解决更复杂的问题,比如区间修改和区间查询等。 对于可持久化splay树的学习过程,可以按照以下步骤进行: 1. 理解splay树的基本原理和操作,包括旋转、插入、删除和查找等。 2. 学习如何构建可持久化splay树,包括复制节点、更新版本和保存历史版本等。 3. 掌握可持久化splay树的常见应用场景,比如区间修改和区间查询等。 4. 深入了解与可持久化splay树相关的其他数据结构和算法,比如可持久化线段树等。 在解决问题时,可以使用二分法来确定答案,一般称为二分答案。通过对答案进行二分,然后对每个答案进行检查,以确定最终的结果。这种方法可以应用于很多问题,比如引用中提到的在线询问问题。 综上所述,可持久化splay是一种对splay树进行修改和查询的扩展,可以通过复制节点来创建新的版本,并且可以与其他数据结构相结合解决更复杂的问题。学习过程中可以按照一定的步骤进行,并且可以使用二分法来解决一些特定的问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [[学习笔记]FHQ-Treap及其可持久化](https://blog.csdn.net/weixin_34283445/article/details/93207491)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [可持久化数据结构学习笔记](https://blog.csdn.net/weixin_30376083/article/details/99902410)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值