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、付费专栏及课程。

余额充值