您的位置:首页 > 产品设计 > UI/UE

POJ 1785 Binary Search Heap Construction 【笛卡尔树构造,线段树RMQ(Range Max/Min Query)】

2013-01-24 20:24 597 查看
题目注意: 两个要求,1. 第一关键字满足搜索序,2. 第二关键字满足堆的性质。

1. 这道题目的标准(简单)解法:笛卡尔树

  首先将第一关键字(搜索序的关键字)排序(笛卡尔树中序遍历结果是按照第一关键字升序的),然后逐个向树中插入元素,这时只需要考虑后插入的元素的优先级即可。

a、优先级比上一个节点优先级高:将这个节点调整为根节点。

b、优先级比上一个节点优先级低:将这个节点设为当前节点的右儿子。

2. 但是还有: 分治+RMQ, 其中,RMQ问题有两种方法:线段树和Sparse Table算法。

依然是现按第一关键字排序,然后就是区间询问最大值,这个最大值就是整个树的根,然后分别对左右两个区间进行查询即可。

笛卡尔树定义:

笛卡尔树是一棵二叉树,树的每个节点有两个值,一个为key,一个为value。光看key的话,笛卡尔树是一棵二叉搜索树,每个节点的左子树的key都比它小,右子树都比它大;光看value的话,笛卡尔树有点类似堆,根节点的value是最小(或者最大)的,每个节点的value都比它的子树要大。

补充:

Treap:treap和笛卡尔树的结构是相同的。

这道题目就是一道裸笛卡尔树的构造:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

struct node {
int val, lson, rson, fa;
char s[100];
} a[50005];
int n;
bool cmp(node x, node y) {
return strcmp(x.s, y.s) < 0;
}
void Insert(int now) {
int j = now - 1;
while (a[j].val < a[now].val) j = a[j].fa;
a[now].lson = a[j].rson;
a[j].rson = now;
a[now].fa = j;
}
void Traval(int now) {
if (now == 0) return ;
printf("(");
Traval(a[now].lson);
printf("%s/%d", a[now].s, a[now].val);
Traval(a[now].rson);
printf(")");
}
int main() {
while (scanf("%d", &n) == 1 && n) {
for (int i=1; i<=n; i++) {
scanf(" %[a-z]/%d", a[i].s, &a[i].val);
a[i].lson = a[i].rson = a[i].fa = 0;
}
sort(a+1, a+n+1, cmp);
a[0].val = 0x3f3f3f3f;
a[0].lson = a[0].rson = a[0].fa = 0;

for (int i=1; i<=n; i++)
Insert(i);
Traval(a[0].rson);
printf("\n");
}
return 0;
}


线段树RMQ版本:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

struct node {
char s[100];
int val;
} a[50005];
int n, v[50005<<2];

void build(int l, int r, int rt) {
if (l == r) {
v[rt] = l;
return ;
}
int mid = (l + r) >> 1;
build(l, mid, rt<<1);
build(mid+1, r, rt<<1|1);
v[rt] = (a[v[rt<<1]].val > a[v[rt<<1|1]].val) ? v[rt<<1] : v[rt<<1|1];
}
int query(int L, int R, int l, int r, int rt) {
if (L <= l && r <= R)
return v[rt];
int ret1, ret2, mid = (l + r) >> 1;

ret1 = ret2 = 0;
if (L <= mid) ret1 = query(L, R, l, mid, rt<<1);
if (mid < R) ret2 = query(L, R, mid+1, r, rt<<1|1);
if (ret1 == 0) return ret2;
if (ret2 == 0) return ret1;
return (a[ret1].val > a[ret2].val) ? ret1 : ret2;
}
void print(int l, int r) {
if (l > r) return ;
if (l == r) {
printf("(%s/%d)", a[l].s, a[l].val);
return ;
}
int m = query(l, r, 1, n, 1);
printf("(");
print(l, m-1);
printf("%s/%d", a[m].s, a[m].val);
print(m+1, r);
printf(")");
}
bool cmp(node x, node y) {
return strcmp(x.s, y.s) < 0;
}
int main() {
while (scanf("%d", &n) == 1 && n) {
for (int i=1; i<=n; i++)
scanf(" %[a-z]/%d", a[i].s, &a[i].val);

sort(a+1, a+n+1, cmp);
build(1, n, 1);
print(1, n);
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: