题目描述
笛卡尔树(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)和满足上述的三个条件。
给出一系列点,构建出它们的笛卡尔树,或检测构建出它们的笛卡尔树是不可能的。
输入输出格式
输入格式:
第一行包括一个整数N(1 <= N <= 50 000),表示你要构建的笛卡尔树的点的对数。
接下来N行包括两个数字,k,a,|k|, |a| <= 30 000,保证每行的k和a是不同的。
输出格式:
如果能构建出笛卡尔树则在第一行输出YES否则输出NO。
如果是YES,则在接下来N行输出这棵树。第i+1行输出第i个结点的父亲,左儿子,右儿子。如果这个结点无父亲或者儿子,则用0代替。
输入保证能构建出笛卡尔树的只有一种情况。
输入输出样例
输入样例#1:
7
5 4
2 2
3 9
0 5
1 3
6 6
4 11
输出样例#1:
YES
2 3 6
0 5 1
1 0 7
5 0 0
2 4 0
1 0 0
3 0 0
内容概括:
插入n个双关键字节点构建数据结构使其同时满足堆和二叉搜索树的特性。
例如样例:
关键字1满足二叉搜索树的性质(中序遍历为0,1,2,3,4,5,6)
关键字2(优先级)满足堆的性质
解法
尽管本题时间效率最高,写法最简洁的是单调栈(线性时间复杂度),但同样可以用FHQ平衡树实现,代码相当简洁但效率较低。
#include<iostream>
#include<algorithm>
using namespace std;
struct Node{
int pri;//第二关键字,优先级
int key;//第一关键字,键值
int ind;//在原数组中的编号
int fa;//父节点
int ls;//左儿子
int rs;//右儿子
}fhq[50010],tree[50010],ans[50010];
int cnt,rt=1;
int cmp(Node x,Node y)
{
return x.pri<y.pri;
}
int cmp2(Node x,Node y)
{
return x.ind<y.ind;
}
inline void Split(int u,int key,int &L,int &R)
{
if(!u)
{
L=R=0;
return;
}
if(tree[u].key<=key)
{
L=u;
Split(tree[u].rs,key,tree[u].rs,R);
}
else
{
R=u;
Split(tree[u].ls,key,L,tree[u].ls);
}
return;
}//按键值分裂成以L,R为根的两棵子树,FHQ基操
inline int Merge(int L,int R)
{
if(!L||!R) return L+R;
if(tree[L].pri<tree[R].pri)//堆顶最小
{
tree[L].rs=Merge(tree[L].rs,R);
return L;
}
else
{
tree[R].ls=Merge(L,tree[R].ls);
return R;
}
}//按优先级合并两个子树,返回合并后树的根
inline void new_node(int ind)
{
cnt++;
tree[cnt]=fhq[ind];
}//新建一个节点(cnt)
inline void Insert(int ind)
{
int L,R;
Split(rt,fhq[ind].key,L,R);//按键值分裂成两个子树
new_node(ind);//新建节点
rt=Merge(Merge(L,cnt),R);//合并L,cnt,R
}
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>fhq[i].key>>fhq[i].pri;
fhq[i].ind=i;
}
sort(fhq+1,fhq+n+1,cmp);
new_node(rt);
for(int i=2;i<=n;i++) Insert(i);
for(int i=1;i<=n;i++)
{
tree[tree[i].ls].fa=i;
tree[tree[i].rs].fa=i;
}
for(int i=1;i<=n;i++)
{
ans[i].fa=tree[tree[i].fa].ind;
ans[i].ls=tree[tree[i].ls].ind;
ans[i].rs=tree[tree[i].rs].ind;
ans[i].ind=fhq[i].ind;
}
sort(ans+1,ans+n+1,cmp2);
cout<<"YES\n";
for(int i=1;i<=n;i++) cout<<ans[i].fa<<' '<<ans[i].ls<<' '<<ans[i].rs<<endl;
return 0;
}