题目:
http://poj.org/problem?id=2201
题意:
给出一个n,在给出n对数(且命名为x,y),构建一棵树,满足以下条件:
- 对树上任意一个节点,有x > leftson_x 且x > rigthson_x
- 对树上任意一个节点,有y > father_y
构建完成后,输出每个点的父节点,左子节点,右子节点,没有的以0代替
思路:
笛卡尔树模板题。笛卡尔树每个节点有两个值,且称为val和pri,满足以下条件:
- 满足任意节点的val,大于其左子节点的val,小于其右子节点的val。
- 满足任意节点的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;
}
来源:CSDN
作者:霜刃未曾试
链接:https://blog.csdn.net/discreeter/article/details/76666096