笛卡尔树(Cartersian Tree)2016.9.12

参考:http://blog.csdn.net/zh_qd1014/article/details/6879083(非常值得一看哦


一、

笛卡尔树是一棵二叉树,树的每个节点有两个值,一个为 key,一个为 val

光看 key 的话,笛卡尔树是一棵二叉搜索树,每个节点的左子树的 key 都比它小,右子树都比它大

光看 value 的话,笛卡尔树有点类似堆,根节点的 val是最小(或者最大)的,每个节点的 value 都比它的子树要小(或者大)


二、树的构造

如果 key 值是有序的,那么笛卡尔树的构造是线性的


如果我们要用数组 A[1 ... n] 构造出一棵有 n 个节点的笛卡尔树

为了方便理解,不妨假设每个节点的 key 为数组元素的下标 i,val 为 A[i] 来建树,这样也保证了 key 的有序性

再假设这里的笛卡尔树为一种特殊的最小堆,那么树的根节点是数组 A 中最小元素的下标 i,根节点的左右孩子分别由数组 A[1 ... i-1] 和数组 A[i+1 ... n] 构造



图 1 原数组



图 2 笛卡尔树最终生成结果(节点内容:key 即数组元素下标)(中序遍历可得到原数组)



图 3 笛卡尔树最终生成结果(节点内容:val 即数组元素)




图 4 第一个插入树的节点



图 5 第二个元素比树中最右边路径上的节点 1 的 val 大,故成为节点 1 的右孩子



图 6 第三个元素的 val 比树中最右边路径上节点 1、2 的 val 都小,将节点 1 设为该节点的左孩子



图 7 第四个元素的 val 比树中最右边路径上节点 3 的 val 大,故成为根节点 3 的右孩子



图 8 第五个节点元素的 val 比树中最右边的路径上的节点 3、4 的 val 都大,故成为节点 4 的右孩子



图 9 第六个节点元素的 val 比树中最右边路径上节点 5 的 val 小,但比节点 4 的 val 大,故成为节点 4 的右孩子,将节点 5 设为该节点的左孩子



图 10 第七个元素的 val 比树中最右边路径上节点 6 的 val 大,故成为节点6的右孩子



图 11 第八个元素的 val 比树中最右边路径上节点 7 的 val 小,但比节点 6 的 val 大,故该节点称为节点 6 的右孩子,节点 7 成为该节点的左孩子


图 12 第九个元素的 val 比树中最右边路径上节点 8 的 val 大,故成为节点 8 的右孩子



图 13 第十个元素的 val 比树中最右边路径上的节点 9、8、6、4 的 val 都小,但比节点 3 的 val 大,故成为节点 3 的右孩子,节点 4 成为该节点的左孩子


构造过程中需要用栈维护笛卡尔树的一条右链,即根结点、根结点的右儿子、根结点的右儿子的右儿子 …… 组成的链,注意这些元素的 key 和 val 都是递增的


每个节点最多入栈、出栈一次,因此时间复杂度为 O(n)


SGU 155 Cartesian Tree
POJ 2201 Cartesian Tree

题意:

建好笛卡尔树后输出每个结点(按照输入的顺序编号)的父亲结点和两个儿子节点的编号

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#include <cmath>
#include <cctype>
#include <bitset>
#include <ctime>

using namespace std;

#define REP(i, n) for (int i = 0; i < (n); ++i)

typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef pair<int, int> Pair;

const ull mod = 1e9 + 7;
const int INF = 0x7fffffff;
const int maxn = 5e4 + 10;

struct Cartesian {
    int id, key, val, pre, lson, rson;
    bool operator < (const Cartesian& a) const {
        return key < a.key;
    }
};

Cartesian tree[maxn];
stack<int> Stack;
int N;
int pos[maxn];

int main()
{
#ifdef __AiR_H
    freopen("in.txt", "r", stdin);
#endif // __AiR_H
    scanf("%d", &N);
    for (int i = 1; i <= N; ++i) {
        tree[i].pre = tree[i].lson = tree[i].rson = 0;
    }
    for (int i = 1; i <= N; ++i) {
        tree[i].id = i;
        scanf("%d %d", &tree[i].key, &tree[i].val);
    }
    sort(tree+1, tree+1+N);
    pos[tree[1].id] = 1;
    Stack.push(1);
    for (int i = 2; i <= N; ++i) {
        pos[tree[i].id] = i;
        int father = 0, son = 0;
        while (!Stack.empty()) {
            int t = Stack.top();
            if (tree[i].val > tree[t].val) {
                father = t;
                break;
            }
            son = t;
            Stack.pop();
        }
        tree[i].pre = father;
        tree[father].rson = i;
        tree[i].lson = son;
        tree[son].pre = i;
        Stack.push(i);
    }
    printf("YES\n");
    for (int i = 1; i <= N; ++i) {
        int pos_t = pos[i];
        printf("%d %d %d\n", tree[tree[pos_t].pre].id, tree[tree[pos_t].lson].id, tree[tree[pos_t].rson].id);
    }
    return 0;
}

HDU 1506 Largest Rectangle in a Histogram
POJ 2559 Largest Rectangle in a Histogram

参考:http://blog.csdn.net/ophunter_lcm/article/details/9327235

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#include <cmath>
#include <cctype>
#include <bitset>
#include <ctime>

using namespace std;

#define REP(i, n) for (int i = 0; i < (n); ++i)

typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef pair<int, int> Pair;

const ull mod = 1e9 + 7;
const int INF = 0x7fffffff;
const int maxn = 1e5 + 10;

struct Cartesian {
    ll val, pre, lson, rson;
};

Cartesian tree[maxn];
ll Stack[maxn];
ll n;
ll ans = 0;

ll build(void);
ll dfs(ll root);

int main()
{
#ifdef __AiR_H
    freopen("in.txt", "r", stdin);
#endif // __AiR_H
    while (scanf("%I64d", &n) != EOF && n != 0) {
        for (ll i = 1; i <= n; ++i) {
            tree[i].pre = tree[i].lson = tree[i].rson = 0;
        }
        for (ll i = 1; i <= n; ++i) {
            scanf("%I64d", &tree[i].val);
        }
        ll root = build();
        ans = 0;
        dfs(root);
        printf("%I64d\n", ans);
    }
    return 0;
}

ll build(void)
{
    ll size = 0;
    Stack[++size] = 1;
    for (ll i = 2; i <= n; ++i) {
        ll father = 0, son = 0;
        while (size != 0) {
            ll top = Stack[size];
            if (tree[i].val > tree[top].val) {
                father = top;
                break;
            }
            son = top;
            --size;
        }
        tree[i].pre = father;
        tree[father].rson = i;
        tree[i].lson = son;
        tree[son].pre = i;
        Stack[++size] = i;
    }
    return Stack[1];
}

ll dfs(ll root)
{
    if (root == 0) {
        return 0;
    }
    ll num = dfs(tree[root].lson) + dfs(tree[root].rson) + 1;
    ll ans_t = num * tree[root].val;
    if (ans_t > ans) {
        ans = ans_t;
    }
    return num;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值