伸展树真好玩

競賽歷程 Add comments416 views

伸展树(Splay)这个东西,转来转去的,真好玩。

今天第一次写Splay,Splay操作太强大了。Splay(x,y)操作为把节点x旋转到y节点下面,均摊时间复杂度为O(logN)。

有了这个东西,就能实现两棵Splay合并,要求一棵比另一棵所有元素都小。合并两棵伸展树a,b(a<b),方法为把a中的最大值c,splay到a的根节点,此时a树根节点的右子树为空,接下来把b树接到c的右子树就行了。

有了合并这个东西,Splay的删除就比任何平衡树的删除都简单了。方法就是先把要删除的节点Splay到根位置,然后合并根节点的两棵子树即可(有点像左偏树)。

Splay太好玩了,继续研究。

NOIP2007 统计数字 Splay

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/* 
 * Problem: NOIP2007 统计数字
 * Author: Guo Jiabao
 * Time: 2009.5.16 17:16
 * State: Solved
 * Memo: 伸展树 Splay 插入 删除 合并 
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
const int MAXN=200001;
using namespace std;
struct SplayTree
{
	struct ST_Node
	{
		ST_Node *left,*right,*father;
		int value,weight;
	}*root;
	int SC;
	ST_Node SE[MAXN];
	void ZIG(ST_Node *x)
	{
		ST_Node *y=x->father;
		// x->right
		y->left = x->right;
		if (x->right)
			x->right->father=y;
		// y->father
		x->father = y->father;
		if (y->father)
		{
			if (y==y->father->left)
				y->father->left = x;
			else
				y->father->right = x;
		}
		// y
		x->right = y;
		y->father = x;
	}
	void ZAG(ST_Node *x)
	{
		ST_Node *y=x->father;
		// x->left
		y->right = x->left;
		if (x->left)
			x->left->father=y;
		// y->father
		x->father = y->father;
		if (y->father)
		{
			if (y==y->father->left)
				y->father->left = x;
			else
				y->father->right = x;
		}
		// y
		x->left = y;
		y->father = x;
	}
	void Splay(ST_Node *x,ST_Node *y)
	{
		while (x->father != y)
		{
			if (x->father->father == y)
			{
				if (x->father->left == x)
					ZIG(x);
				else
					ZAG(x);
			}
			else if (x->father->father->left == x->father)
			{
				if (x->father->left == x)
				{
					ZIG(x->father);
					ZIG(x);
				}
				else
				{
					ZAG(x);
					ZIG(x);
				}
			}
			else
			{
				if (x->father->right == x)
				{
					ZAG(x->father);
					ZAG(x);
				}
				else
				{
					ZIG(x);
					ZAG(x);
				}
			}
		}
		if (y==0)
			root=x;
	}
	void insert(int value)
	{
		ST_Node **p=&root,*y=0;
		for (;;)
		{
			if (!*p)
			{
				*p=SE+ (++SC);
				(*p)->left = (*p)->right = 0;
				(*p)->value = value;
				(*p)->weight = 1;
				(*p)->father = y;
				Splay(*p,0);
				break;
			}
			y=*p;
			if (value == (*p)->value)
			{
				(*p)->weight ++;
				Splay(*p,0);
				break;
			}
			else if (value < (*p)->value)
				p=&(*p)->left;
			else
				p=&(*p)->right;
		}
	}
	ST_Node* join(ST_Node *a,ST_Node *b)
	{
		if (a) a->father=0;
		if (b) b->father=0;
		if (!b)	return a;
		if (!a) return b;
		ST_Node *c=a;
		for (;c->right;c=c->right);
		Splay(c,0);
		c->right=b;
		b->father=c;
		return c;
	}
	void remove(ST_Node *x)
	{
		Splay(x,0);
		root=join(x->left,x->right);
	}
	void delmin(int &min,int &cnt)
	{
		ST_Node *x=root;
		for (;x->left;x=x->left);
		min=x->value; cnt=x->weight;
		remove(x);
	}
}Splay;
int N;
int main()
{
	int i,c,v;
	freopen("pcount.in","r",stdin);
	freopen("pcount.out","w",stdout);
	scanf("%d",&N);
	for (i=1;i<=N;i++)
	{
		scanf("%d",&c);
		Splay.insert(c);
	}
	while (Splay.root)
	{
		Splay.delmin(v,c);
		printf("%d %d\n",v,c);
	}
	return 0;
}

Maybe you like

标签:, , , ,


7 Responses to “伸展树真好玩”

  1. cai0715 Says:
    TheWorld Windows XP

    @-@…

    不会Splay的菜飘过…

    [回复]

  2. CmYkRgB123 Says:
    Firefox 3.0.10Windows XP

    许多大牛都只会Splay,无视掉其他的平衡树,例如cqx,zkw

    [回复]

  3. wjjwjj101 Says:
    Internet Explorer 8.0;Windows XP

    cqx是会treap的

    [回复]

  4. CmYkRgB123 Says:
    Firefox 3.0.10Ubuntu

    #3 我错了 不要BS我

    [回复]

  5. cai0715 Says:
    TheWorld Windows XP

    #3~~典型的网易游戏表情。。。

    #83..

    [回复]

  6. CmYkRgB123 Says:
    Firefox 3.0.10Ubuntu

    #3 我的意思是回复三楼 我不明白你的意思

    [回复]

  7. cai0715 Says:
    TheWorld Windows XP

    …刚才在某群发了这个符号#3,人家问我是不是玩过网易的游戏、、、我说是。。。

    然后我来了你的Blog逛,结果又发现了这个符号,于是就。。。

    Sorry,没理解神牛#3的真正意思~ Orz

    [回复]

Leave a Reply

38 queries. 0.502 seconds. Designed by NattyWP .
Images by desEXign.