poj2528-Mayor's posters的树堆解法

 
            二叉搜索树的有序性质使得查找操作时间时长为O(log N),而不需要遍历整个数组。但是如果二叉搜索树退化为单链程序效率会快速下降,因此出现了一些方法使得二叉搜索树趋向平衡,treap也是其中较为简单的一种。
           树堆在普通二叉搜索树的每个节点上新增了一个随机数,每次在二叉搜索树插入一个节点后,进行左旋或者右旋使之满足堆序性质,值得注意的是,这个随机数仅仅是为了是树趋向平衡,本身可能没有任何意义。
           下面是实现树堆的代码,包括了一些通常的操作例如删除,插入等等。
           下面的代码是poj2528- Mayor's posters的树堆解法。不过提交时出现了RE,但测试数据(已经上传,点击打开链接)可以通过,如果大家发现了bug欢迎交流。

   
   
//解题思路是,根据区间建立搜索树,每个节点增加一个随机数,满足堆序性质,使树尽可能平衡
//每次新加入一个区间时,对树进行操作,使所有与将要插入的区间有交集的部分进行 删除,修改
//等等,这些都在change函数中进行,最后根据树求出所有的颜色
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
struct sNode { // Treap节点
int a, b; // 区间 [a, b]
int number; // 颜色编号
int weight; // weight域
sNode *lch, *rch; // 左右儿子的指针
sNode(int a_, int b_, int n_) :
a(a_), b(b_), number(n_), weight(rand()) {// 构造函数初始化
lch = rch = NULL;
}
};
typedef sNode* pNode; // 定义指针类型
pNode root; // 根指针
int result[10010];
void leftRotate(pNode &rt) // 左旋
{
pNode p = rt->lch;
rt->lch = p->rch;
p->rch = rt;
rt = p;
return;
}
void rightRotate(pNode &rt) { // 右旋
pNode p = rt->rch;
rt->rch = p->lch;
p->lch = rt;
rt = p;
return;
}
void removeAll(pNode &rt) { // 删除所有节点
if (!rt)
return;
removeAll(rt->lch);
removeAll(rt->rch);
delete rt;
rt = NULL;
return;
}
void insert(pNode tmp, pNode &rt) { // 递归插入节点
if (!rt) { // 如果当前节点为空的叶子节点
rt = tmp;
return;
}
if (tmp->a < rt->a) { // 插入值小于当前值,插入左子树
insert(tmp, rt->lch);
if (rt->lch->weight < rt->weight) // 维护weight域
leftRotate(rt);
} else { // 插入值大于等于当前值,插入右子树
insert(tmp, rt->rch);
if (rt->rch->weight < rt->weight) // 维护weight域
rightRotate(rt);
}
return;
}
void remove(pNode &rt) {
if (!rt)
return; // 如果访问到空节点,删除值不存在
if (!rt->lch && !rt->rch) { // 没有儿子,直接删除
delete rt;
rt = NULL;
return;
}
if (!rt->rch) { // 只有左儿子,将左儿子旋转到当前位置
leftRotate(rt);
remove(rt->rch); // 继续递归删除
return;
}
if (!rt->lch) { // 只有右儿子,将右儿子旋转到当前位置
rightRotate(rt);
remove(rt->lch); // 继续递归删除
return;
}
if (rt->lch->weight < rt->rch->weight) { // 两个儿子都存在,选择权值小的一个
leftRotate(rt);
remove(rt->rch);
} else {
rightRotate(rt);
remove(rt->lch);
}
return;
}
void change(pNode &rt, int a, int b) { // 处理treap,使所有区间都与[a, b]无交集
if (rt == NULL)
return;
if (a > rt->b) { //递归处理右节点
change(rt->rch, a, b);
return;
}
if (b < rt->a) { //递归处理左节点
change(rt->lch, a, b);
return;
}
if (a <= rt->a && b >= rt->b) { // 删除该节点
remove(rt);
change(root, a, b); // 再次遍历
return;
}
if ((a == rt->a) && b < rt->b) { // 删除区间相交的部分
rt->a = b + 1;
return;
}
if (a > rt->a && (b == rt->b)) { // 删除区间相交的部分
rt->b = a - 1;
return;
}
if (a > rt->a && b < rt->b) { // 区间分为 两部分,修改并插入
pNode tmp = new sNode(b + 1, rt->b, rt->number);
tmp->weight = rt->weight + 1;
rt->b = a - 1;
insert(tmp,rt->rch);
return;
}
if (a < rt->a && b < rt->b) {
rt->a = b + 1;
change(rt->lch, a, b);
return;
}
if (a > rt->a && b > rt->b) {
rt->b = a - 1;
change(rt->rch, a, b);
return;
}
printf("!!!!!!!!change default!!!!\n");
}
void sum(pNode &rt) { // 将所有存在的颜色标记为1
if (rt == NULL)
return;
result[rt->number] = 1;
sum(rt->lch);
sum(rt->rch);
return;
}
int main() {
srand(time(NULL)); //随机种子
int t; // 测试组数
scanf("%d", &t);
while (t--) {
int n;
scanf("%d", &n);
int a, b;
root = NULL; // 根节点
pNode temp;
for (int i = 0; i < n; i++) {
scanf("%d %d", &a, &b);
temp = new sNode(a, b, i); // 新建节点
change(root, a, b); // !!!! 对之前的树进行处理,是所有的区间都与要插入的区间无交集
insert(temp, root); // 插入
result[i] = 0; // 初始化 颜色标识数组
}
sum(root); // 遍历treap,求所有颜色
int s = 0;
for (int i = 0; i < n; i++)
s += result[i];
printf("%d\n", s); // 输出颜色数
removeAll(root); // 清空treap
}
return 0;


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值