POJ 2201 Cartesian Tree 笛卡尔树裸题加讲解

扶醉桌前 提交于 2019-11-30 10:01:43

题目:

http://poj.org/problem?id=2201

题意:

给出一个n,在给出n对数(且命名为x,y),构建一棵树,满足以下条件:

  • 对树上任意一个节点,有x > leftson_x 且x > rigthson_x
  • 对树上任意一个节点,有y > father_y

构建完成后,输出每个点的父节点,左子节点,右子节点,没有的以0代替

思路:

笛卡尔树模板题。笛卡尔树每个节点有两个值,且称为val和pri,满足以下条件:

  1. 满足任意节点的val,大于其左子节点的val,小于其右子节点的val。
  2. 满足任意节点的pri,要么全部小于其父节点的pri,要么全部大于其父节点的pri,视题目有所不同,此题是第二种情况。

可以在O(n)的时间内构建一颗笛卡尔树(此处按pri的第二种情况建树)。首先对所有节点按val从小到大排序,然后维护一个单调栈,栈中元素的pri从栈底到栈顶依次递增,这个栈实际上维护的是树的最右链,每次有新元素加入时,从栈顶向栈底遍历,栈中元素的pri大于新元素的pri的话,就直接出栈,直到遇到栈中一个元素的pri小于新元素的pri,那么把这个新元素挂到这个栈中元素的右儿子上,把刚刚出栈的最后一个元素挂到新元素的左儿子上,可以发现这样是满足建树的条件1。就这样一直进行下去,到最后,栈底的元素就是笛卡尔树的树根。
此题用treap会TLE

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>

using namespace std;

const int N = 50000 + 10, INF = 0x3f3f3f3f;

int root;

struct node
{
    int val, pri, fat, id, son[2];
    friend bool operator< (node a, node b)
    {
        return a.val < b.val;
    }
    void init(int _val, int _pri, int _fat, int _id)
    {
        val = _val, pri = _pri, fat = _fat, id = _id;
        son[0] = son[1] = 0;
    }
}tr[N];
int stk[N], top;
int ans_fat[N], ans_l[N], ans_r[N];
int cartesian_build(int n)
{
    top = 0;
    for(int i = 1; i <= n; i++)
    {
        int k = top;
        while(k > 0 && tr[stk[k-1]].pri > tr[i].pri) k--;//栈中元素的pri大于新元素的pri就直接出栈
        if(k != 0) //栈中还有元素,就把新元素挂到这个元素的右儿子上
        {
            tr[i].fat = stk[k-1];
            tr[stk[k-1]].son[1] = i;
//            ans_fat[tr[i].id] = tr[stk[k-1]].id; //注释的这些去掉就不用dfs了,只不过为了熟悉笛卡尔树所以又写了个dfs求答案
//            ans_r[tr[stk[k-1]].id] = tr[i].id;
        }
        if(k != top) //有元素出栈,则把出栈的最后一个元素挂到新元素的左儿子上
        {
            tr[stk[k]].fat = i;
            tr[i].son[0] = stk[k];
//            ans_fat[tr[stk[k]].id] = tr[i].id;
//            ans_l[tr[i].id] = tr[stk[k]].id;
        }
        stk[k++] = i;
        top = k;
    }
    return stk[0];
}
void dfs(int x, int fat)
{
    if(! x) return;
    ans_fat[tr[x].id] = tr[fat].id;
    ans_l[tr[x].id] = tr[tr[x].son[0]].id;
    ans_r[tr[x].id] = tr[tr[x].son[1]].id;
    dfs(tr[x].son[0], x);
    dfs(tr[x].son[1], x);
}
int main()
{
    int n;
    while(~ scanf("%d", &n))
    {
        int a, b;
        tr[0].init(0, 0, 0, 0);
        for(int i = 1; i <= n; i++)
        {
            scanf("%d%d", &a, &b);
            tr[i].init(a, b, 0, i);
        }
        sort(tr + 1, tr + 1 + n);
        root = cartesian_build(n);
        dfs(root, 0);
        puts("YES");
        for(int i = 1; i <= n; i++) printf("%d %d %d\n", ans_fat[i], ans_l[i], ans_r[i]);
    }
    return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!