伸展树删除元素非常方便。。

View Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <stdlib.h>
#include <math.h>
#include <algorithm>
#include <time.h>
using namespace std;
int left[100010], right[100010], pf[100010];
int value[100010];
int num[100010]; //记录该数出现次数
int yy[100010];
int root;
int flag = 0;
void debug( )
{
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
}
//右旋
inline void zig( int n )
{
int m = pf[n];
left[m] = right[n];
pf[right[n]] = m;
right[n] = m;
if(left[pf[m]] == m )
left[pf[m]] = n;
else
right[pf[m]] = n;
pf[n] = pf[m];
pf[m] = n;
// return n;
}
//左旋
inline void zag( int n )
{
int m = pf[n];
right[m] = left[n];
pf[left[n]] = m;
left[n] = m;
if(left[pf[m]] == m )
left[pf[m]] = n;
else
right[pf[m]] = n;
pf[n] = pf[m];
pf[m] = n;
//return n;
}
inline int splay(int n, int p)
{
while( pf[n] != p )
{
int px = pf[n];
int pfather = pf[px];
if( pfather == p )
{
if( n == left[px])
zig(n);
else
zag(n);
}
else
{
if( left[pfather] == px )
{
if( left[px] == n )
{
zig(px);
zig(n);
}
else
{
zag(n);
zig(n);
}
}
else if(right[pfather] == px)
{
if( right[px] == n )
{
zag(px);
zag(n);
}
else
{
zig(n);
zag(n);
}
}
}
}
return n;
}
void insert( int n )
{
int t = root;
if( root == -1 )
{
root = n;
left[root] = -1;
right[root] = -1;
pf[root] = -1;
root = n;
num[n]++;
return;
}
while( 1 )
{
if( t > n )
{
if( left[t] == -1 )
{
left[t] = n;
pf[n] = t;
left[n] = -1;
right[n] = -1;
num[n]++;
root = splay(n,-1);
return;
}
t = left[t];
}
else if( t < n )
{
if( right[t] == -1)
{
right[t] = n;
pf[n] = t;
left[n] = -1;
right[n] = -1;
num[n]++;
root = splay(n,-1);
return;
}
t = right[t];
}
else
{
root = splay(n,-1);
num[n]++;
return;
}
}
}
void preordertravel( int n )
{
if ( n != -1 ) {
preordertravel(left[n]);
if( flag == 0 )
{
printf("%d",yy[n]);
for( int i = 1; i < num[n]; i++)
printf(" %d", yy[n]);
flag = 1;
}
else
{
for( int i = 0; i < num[n]; i++)
printf(" %d",yy[n]);
}
preordertravel(right[n]);
}
}
int get_Min( int n )
{
int t = n, p;
while( t != -1 )
{
p = t;
t = left[t];
}
return p;
}
int get_Max( int n )
{
int t = n, p;
while( t != -1 )
{
p = t;
t = right[t];
}
return p;
}
int get_next( int n )
{
if( num[n] != 0 )
return n;
else if( right[n] == -1 )
return 0;
else if( left[right[n]] != -1 )
return get_Min(left[right[n]]);
else
return right[n];
}
int get_prev( int n)
{
if( num[n] != 0 )
return n;
else if( left[n] == -1 )
return 0;
else if(right[left[n]] != -1 )
return get_Max(right[left[n]]);
else
return left[n];
}
//将根节点删除后,将左子树右子树合并
int joint( int p, int q )
{
if( p )
pf[p] = -1;
if( q )
pf[q] = -1;
if( p == -1 && q == -1 )
return 0; //如果两子树为空
if( p == -1 ) //如果左子树为空
return q;
if( q == -1 ) //如果右子树为空
return p;
p = get_Max( p );
root = splay(p,-1);
right[p] = q;
pf[q] = p;
return p;
}
void del( int n )
{
n = splay(n,-1);
root = joint(left[n], right[n]);
}
int find( int p, int x )
{
if( p == -1 )
return -1;
if( yy[p] == x )
return 1;
else if( yy[p] > x )
return find(left[p], x);
else
return find(right[p], x);
}
int main( )
{
int N, M, a, b;
char str[100];
while ( scanf("%d%d", &N, &M), N)
{
memset(left, 0, sizeof(left));
memset(right,0, sizeof(right));
memset(pf, 0, sizeof(pf));
memset(num, 0,sizeof(num));
memset(yy, 0, sizeof(yy));
root = -1;//根结点
int sum = 0;
for( int i = 1; i <= N; i++)
{
scanf("%d", &value[i]);
yy[i] = value[i];
}
sort(yy + 1, yy + N + 1);
int cnt = unique(yy + 1,yy + N + 1) - yy - 1;
for( int i = 1; i <= N; i++)
{
value[i] = lower_bound(yy + 1, yy + cnt + 1, value[i]) - yy;
insert(value[i]);
}
for( int i = 1; i <= M; i++)
{
scanf("%s", str);
flag = 0;
if( str[0] == 'D' )
{
scanf("%d", &a);
a = lower_bound(yy + 1, yy + cnt + 1, a) - yy;
del( a );
}
else if( str[0] == 'P' )
{
preordertravel(root);
puts("");
}
else if( str[0] == 'F' )
{
scanf("%d",&a);
if( find(root, a) != -1 )
puts("1");
else
puts("-1");
}
}
}
return 0;
}
本文深入探讨了伸展树的特性,特别是其在删除元素方面的高效性,并提供了详细的代码实现,包括插入、删除、旋转等操作,适用于需要快速查找和修改数据结构的场景。

被折叠的 条评论
为什么被折叠?



