poj 3580 SuperMemo splay树模板题

题意:

给一个序列,对其进行各种操作。在对序列仅对操作的处理上,splay是比线段树强大的,虽然均摊复杂度均为logN,但它能支持1:在某个位置插入一些连续的数,2:在某个位置删除一些连续的数。只是splay随便一些200+行。

分析:

网上各种模板介绍漫天飞,这个还算简洁明了。

代码:

//poj 3580
#include <stdio.h>
#define maxN 200000
int N,T,node;
int a[maxN],size[maxN],left[maxN],right[maxN],pre[maxN],key[maxN],add[maxN],rev[maxN],minx[maxN];

void pushdown(int cur)
{
	int ls=left[cur],rs=right[cur];
	if(add[cur]){
		add[ls]+=add[cur],add[rs]+=add[cur];
		key[ls]+=add[cur],key[rs]+=add[cur];
		minx[ls]+=add[cur],minx[rs]+=add[cur];
		add[cur]=0;
	}
	if(rev[cur]){
		rev[ls]=rev[ls]^1,rev[rs]=rev[rs]^1;
		left[cur]=rs,right[cur]=ls;
		rev[cur]=0;
	}
}

void update(int cur)
{
	int ls=left[cur],rs=right[cur];
	size[cur]=size[ls]+size[rs]+1;
	minx[cur]=key[cur];
	if(ls&&minx[ls]<minx[cur])
		minx[cur]=minx[ls];
	if(rs&&minx[rs]<minx[cur])
		minx[cur]=minx[rs];
}

void newnode(int &cur,int v)
{
	cur=++node;
	minx[cur]=key[cur]=v;
	size[cur]=1;
	left[cur]=right[cur]=rev[cur]=add[cur]=0;
}

void build(int &cur,int x,int y,int p)
{
	int mid=(x+y)/2;
	newnode(cur,a[mid]);
	pre[cur]=p;
	if(x==y) return ;
	if(x<mid) build(left[cur],x,mid-1,cur);
	if(mid<y) build(right[cur],mid+1,y,cur);
	update(cur);
}

void init()
{
	for(int i=1;i<=N;++i)
		scanf("%d",&a[i]);
	node=size[0]=left[0]=right[0]=pre[0]=0;
	build(T,0,N+1,0);
}

void leftrotate(int x)
{
	int y=right[x],p=pre[x];
	right[x]=left[y];
	if(right[x])
		pre[right[x]]=x;
	left[y]=x;
	pre[x]=y;
	pre[y]=p;
	if(p==0)
		T=y;
	else
		right[p]==x?right[p]=y:left[p]=y;
	update(x);
}

void rightrotate(int x)
{
	int y=left[x],p=pre[x];
	left[x]=right[y];
	if(left[x])
		pre[left[x]]=x;
	right[y]=x;
	pre[x]=y;
	pre[y]=p;
	if(p==0)
		T=y;
	else
		right[p]==x?right[p]=y:left[p]=y;
	update(x);
}

void splay(int x,int goal)
{
	int y,z;
	while(1){
		if((y=pre[x])==goal)
			break;
		if((z=pre[y])==goal)
			right[y]==x?leftrotate(y):rightrotate(y);
		else{
			if(right[z]==y){
				if(right[y]==x)
					leftrotate(z),leftrotate(y);
				else
					rightrotate(y),leftrotate(z);
			}
			else{
				if(left[y]==x)
					rightrotate(z),rightrotate(y);
				else
					leftrotate(y),rightrotate(z);
			}
		}
	}
	update(x);
}

void rotateto(int k,int goal)
{
	int i=T;
	while(1){
		pushdown(i);
		if(size[left[i]]+1==k)
			break;
		if(k<=size[left[i]])
			i=left[i];
		else
			k-=size[left[i]]+1,i=right[i];
	}
	splay(i,goal);
}

void ADD(int x,int y,int z)
{
	int k;
	rotateto(x,0),rotateto(y+2,T);
	k=left[right[T]];
	add[k]+=z,key[k]+=z,minx[k]+=z;
}

void REVERSE(int x,int y)
{
	int k;
	rotateto(x,0),rotateto(y+2,T);
	k=left[right[T]];
	rev[k]^=1;
}

void REVOLVE(int x,int y,int z)
{
	int k=z%(y-x+1),t;
	if(k){
		rotateto(x,0),rotateto(y+2-k,T);
		t=left[right[T]];
		left[right[T]]=0;
		update(right[T]),update(T);
		rotateto(x+k,0),rotateto(x+k+1,T);
		left[right[T]]=t,pre[t]=right[T];
		update(right[T]),update(T);
	}
}

void INSERT(int x,int y)
{
	rotateto(x+1,0),rotateto(x+2,T);
	newnode(left[right[T]],y);
	pre[left[right[T]]]=right[T];
	update(right[T]),update(T);
}	

void DELETE(int x)
{
	rotateto(x,0),rotateto(x+2,T);
	left[right[T]]=0;
	update(right[T]),update(T);
}

void MIN(int x,int y)
{
	rotateto(x,0),rotateto(y+2,T);
	printf("%d\n",minx[left[right[T]]]);
}

void solve()
{
	int x,y,z,m;
	char s[16];
	scanf("%d",&m);
	while(m--){
		scanf("%s",s);
		if(s[0]=='A'){
			scanf("%d%d%d",&x,&y,&z);
			ADD(x,y,z);
		}else if(s[0]=='R'){
			scanf("%d%d",&x,&y);
			if(s[3]=='E')
				REVERSE(x,y);
			else{
				scanf("%d",&z);
				REVOLVE(x,y,z);
			}
		}else if(s[0]=='I'){
			scanf("%d%d",&x,&y);
			INSERT(x,y);
		}else if(s[0]=='D'){
			scanf("%d",&x);
			DELETE(x);
		}else if(s[0]=='M'){
			scanf("%d%d",&x,&y);
			MIN(x,y);
		}
	}
}

int main()
{
	while(scanf("%d",&N)==1){
		init();
		solve();
	}
	return 0;
}
时间: 2024-10-11 18:25:48

poj 3580 SuperMemo splay树模板题的相关文章

POJ 3580 - SuperMemo - [伸展树splay]

题目链接:http://poj.org/problem?id=3580 Your friend, Jackson is invited to a TV show called SuperMemo in which the participant is told to play a memorizing game. At first, the host tells the participant a sequence of numbers, {A1, A2, ... An}. Then the h

poj 3580 SuperMemo (Splay)

poj 3580 好恶心的题目,真是各种操作都来了个遍 ... 不过Splay树真是一种神奇的东西,通过旋转就能实现各种操作,而且方法也都相差不大 . 题意: 给出一个数字序列,有6种操作: (1) ADD x y d: 第x个数到第y个数加d . (2) REVERSE x y : 将区间[x,y]中的数翻转 . (3) REVOLVE x y t :将区间[x,y]旋转t次,如1 2 3 4 5 旋转2次后就变成4 5 1 2 3 . (4) INSERT x p :在第x个数后面插入p .

POJ 3580 SuperMemo (Splay 区间更新、翻转、循环右移,插入,删除,查询)

SuperMemo Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 13917   Accepted: 4352 Case Time Limit: 2000MS Description Your friend, Jackson is invited to a TV show called SuperMemo in which the participant is told to play a memorizing game

POJ 3580 SuperMemo(伸展树的基本操作)

题目大意:给你六个操作,让你实现这些功能. 解题思路:伸展树的基本应用,用伸展数实现各种功能. SuperMemo Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 10404   Accepted: 3320 Case Time Limit: 2000MS Description Your friend, Jackson is invited to a TV show called SuperMemo in which t

字典树模板题 POJ 2503

1 #include <cstdio> 2 #include <cstring> 3 4 char en[11],fr[11]; 5 int st; 6 struct Tire{ 7 int next[26]; 8 char eng[11]; 9 }node[200005]; 10 void insert(char *s,int cur) 11 { 12 if(*s){ 13 if(!node[cur].next[*s-'a']) 14 node[cur].next[*s-'a']

POJ 3580 SuperMemo

裸Splay区间操作: 内存池+区间加减+区间翻转+插入+删除+维护最值 SuperMemo Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 8552   Accepted: 2801 Case Time Limit: 2000MS Description Your friend, Jackson is invited to a TV show called SuperMemo in which the participa

划分树模板题

原题http://poj.org/problem?id=2104 K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 37130   Accepted: 11974 Case Time Limit: 2000MS Description You are working for Macrohard company in data structures department. After failing

poj3630 Phone List (trie树模板题)

Phone List Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 26328   Accepted: 7938 Description Given a list of phone numbers, determine if it is consistent in the sense that no number is the prefix of another. Let's say the phone catalogu

HDU 1251 Trie树模板题

1.HDU 1251 统计难题  Trie树模板题,或者map 2.总结:用C++过了,G++就爆内存.. 题意:查找给定前缀的单词数量. #include<iostream> #include<cstring> #include<cmath> #include<queue> #include<algorithm> #include<cstdio> #define max(a,b) a>b?a:b #define F(i,a,b