【RMQ&LCA】Cartesian Tree(笛卡尔树)
Time Limit:1000MS Memory Limit:65536K
Total Submit:6 Accepted:6
Description
笛卡尔树(tree.pas/c/cpp)
【问题描述】
让我们考虑一种特殊的二叉查找树,叫做笛卡尔树。回想一下,二叉查找树是有根有序的二叉树,这样,对于它的每一个节点x满足以下条件:在它的左子树的每个节点的数值小于x的数值,它的右子树的每个节点的数值大于x的数值。也就是说,如果我们用L(x)表示结点x的左子树,用R(x)表示结点x右子树,用kx表示该结点x的数值,那么对每个结点x我们有
如果y ∈ L(x),那么ky < kx
如果z ∈ R(x),那么kz > kx
若一棵二叉查找树被称为笛卡尔树,那么它的每一个结点x除了主要数值kx外还有一个附加数值ax,且这个数值符合堆的条件,即
如果y是x的父亲,那么ay < ax
因此,一棵笛卡尔树是一棵有根有序的二叉树,这样,它的每个节点拥有两个数值(k , a)和满足上述的三个条件。
给出一系列点,构建出它们的笛卡尔树,或检测构建出它们的笛卡尔树是不可能的。
Input
第一行包括一个整数N(1 <= N <= 50 000),表示你要构建的笛卡尔树的点的对数。
接下来N行包括两个数字,k,a,|k|, |a| <= 30 000,保证每行的k和a是不同的。
Output
如果能构建出笛卡尔树则在第一行输出YES否则输出NO。
如果是YES,则在接下来N行输出这棵树。第i+1行输出第i个结点的父亲,左儿子,右儿子。如果这个结点无父亲或者儿子,则用0代替。
输入保证能构建出笛卡尔树的只有一种情况。
Sample Input
Sample Output
Hint
本题数据不完整,请在本系统测试通过后到http://poj.org/problem?id=2201 提交完整测试!
Source
Northeastern Europe 2002, Northern Subregion
一开始看错题目,以为输入的第二个数字为K,纠结了很久也没有构造出一棵笛卡尔树。
先把数据按k从小到大排序,所得为树的中序遍历。
找出这棵树中a值最小的为该树的根,在排序中 根 左面a值最小的为该树的左子树,在排序中 根 右面a值最小的为该树的右子树。找最小值时,要用ST算法。
var
n:longint;
a:array[0..50000+1,1..3]of longint;
f:array[0..16]of longint;
mi:array[0..50000+1,0..16,1..2]of longint;
o:array[0..50000+1,1..3]of longint;
procedure init;
var
i:longint;
begin
f[0]:=1;
for i:=1 to 16 do f[i]:=f[i-1]*2;
read(n);
for i:=1 to n do
begin
read(a[i,1],a[i,2]);
a[i,3]:=i;
end;
end;
procedure qsort(l,r:longint);
var
i,j,k:longint;
begin
if l>=r then exit;
i:=l;
j:=r;
k:=a[(l+r) div 2,1];
while i
while a[i,1]
if i<=j then
begin
a[0]:=a[i];
a[i]:=a[j];
a[j]:=a[0];
inc(i);
dec(j);
end;
end;
qsort(l,j);
qsort(i,r);
end;
procedure dfs(l,r:longint);
var
i,t,ft,lt,rt,x:longint;
begin
if r<=l then exit;
t:=trunc(ln(r-l+1)/ln(2));
if mi[l,t,1]
ft:=a[x,3];
lt:=0;
if l<>x then
begin
t:=trunc(ln(x-l)/ln(2));
if mi[l,t,1]
end;
rt:=0;
if r<>x then
begin
t:=trunc(ln(r-x)/ln(2));
if mi[x+1,t,1]
end;
o[ft,2]:=lt;
o[ft,3]:=rt;
o[lt,1]:=ft;
o[rt,1]:=ft;
dfs(l,x-1);
dfs(x+1,r);
end;
procedure main;
var
i,b,t:longint;
begin
for i:=1 to n do mi[i,0,1]:=a[i,2];
for i:=1 to n do mi[i,0,2]:=i;
for t:=1 to trunc(ln(n)/ln(2)) do
for b:=1 to n-f[t]+1 do
if mi[b,t-1,1]>mi[b+f[t-1],t-1,1] then mi[b,t]:=mi[b+f[t-1],t-1]
else mi[b,t]:=mi[b,t-1];
dfs(1,n);
end;
procedure print;
var
i:longint;
begin
writeln('YES');
for i:=1 to n do
writeln(o[i,1],' ',o[i,2],' ',o[i,3]);
end;
begin
init;
qsort(1,n);
main;
print;
end.