【CF797D】 Broken BST

题目

题目描述
Let TT be arbitrary binary tree — tree, every vertex of which has no more than two children. Given tree is rooted, so there exists only one vertex which doesn’t have a parent — it’s the root of a tree. Every vertex has an integer number written on it. Following algorithm is run on every value from the tree TT :

Set pointer to the root of a tree.
Return success if the value in the current vertex is equal to the number you are looking for
Go to the left child of the vertex if the value in the current vertex is greater than the number you are looking for
Go to the right child of the vertex if the value in the current vertex is less than the number you are looking for
Return fail if you try to go to the vertex that doesn’t exist
Here is the pseudo-code of the described algorithm:


bool find(TreeNode t, int x) {
if (t == null)
return false;
if (t.value == x)
return true;
if (x < t.value)
return find(t.left, x);
else
return find(t.right, x);
}
find(root, x);
The described algorithm works correctly if the tree is binary search tree (i.e. for each node the values of left subtree are less than the value in the node, the values of right subtree are greater than the value in the node). But it can return invalid result if tree is not a binary search tree.

Since the given tree is not necessarily a binary search tree, not all numbers can be found this way. Your task is to calculate, how many times the search will fail being running on every value from the tree.

If the tree has multiple vertices with the same values on them then you should run algorithm on every one of them separately.

输入格式
First line contains integer number nn ( 1<=n<=10^{5}1<=n<=10
5
) — number of vertices in the tree.

Each of the next nn lines contains 33 numbers vv , ll , rr ( 0<=v<=10^{9}0<=v<=10
9
) — value on current vertex, index of the left child of the vertex and index of the right child of the vertex, respectively. If some child doesn’t exist then number -1−1 is set instead. Note that different vertices of the tree may contain the same values.

输出格式
Print number of times when search algorithm will fail.

题意翻译
题意:
给一棵二叉搜索树,但是不保证这是一棵正确的二叉搜索树,那么按照二叉搜索树的搜索算法(小往左,大往右),可能找不到某些节点,你的任务是计算有多少节点将不会被遍历到.
输入:
第一行一个整数n(1<=n<=100000)表示节点数目
接下来n行每行三个整数v(0<=v<=10^9),l,r,分别表示节点值,左孩子和右孩子的编号,注意若该子节点不存在用-1表示,不同节点的值可能相同
输出:
找不到的节点有多少个
贡献者:凌幽

输入输出样例
输入 #1复制
3
15 -1 -1
10 1 3
5 -1 -1
输出 #1复制
2
输入 #2复制
8
6 2 3
3 4 5
12 6 7
1 -1 8
4 -1 -1
5 -1 -1
14 -1 -1
2 -1 -1
输出 #2复制
1
说明/提示
In the example the root of the tree in vertex 22 . Search of numbers 55 and 1515 will return fail because on the first step algorithm will choose the subtree which doesn’t contain numbers you are looking for.

思路

我们先假定这有一个非叶子节点 a,他的左节点为l,右节点为r,那么能遍历到l的条件就是l.val<a.val(废话),同理能到r的条件便是r.val>a.val。下面便来考虑一个问题,为了方便便以 r 举例,那么在查询时如何保障对r.val的这个查询能落到a上呢?毕竟查询只有落到a上时才有机会接触到r我们先设r的爷爷节点为fa,假如a是fa的左节点时,那么必须得有r.val<fa.val才行不然就到右子树去了同理假如a是fa右节点时那么必须得有r.val>fa.val。

所以现在能看出来了一个点能被遍历到的条件是这个点的权值比所有的右转节点(下一个走的是右边)的权值要大而比所有左转节点小(同理),所以这个问题用dfs解决就行了,dfs有三个参数,一个是目前的节点号u,一个是一路上右转节点的最大值maxx,一个是所有左转节点的最小值minn,而他能被遍历到的条件是maxx<tree[u].val<minn。

大概就这样了,统计答案时用个map就行了

代码

#include<bits/stdc++.h>
using namespace std;
int n,rt,a[100010],ls[100010],rs[100010],vis[100010],ans;
map<int,bool>mp;
void f(int nw){if(nw==-1)return;vis[nw]=1;}
void dfs(int nw,int l,int r)
{
    if(nw==-1)return ;
    if(a[nw]>l&&a[nw]<r)mp[a[nw]]=1;
    dfs(ls[nw],l,min(r,a[nw])),dfs(rs[nw],max(l,a[nw]),r);
}
void get_ans(){for(int i=1;i<=n;i++)if(!mp[a[i]])ans++;}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d%d%d",&a[i],&ls[i],&rs[i]),f(ls[i]),f(rs[i]);
    for(int i=1;i<=n;i++)if(!vis[i])rt=i;
    dfs(rt,-1,1e9+1),get_ans(),printf("%d\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值