Codeforces 797 D. Broken BST(正难则反 思维题)
Let T 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 T:
- 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 n (1 ≤ n ≤ 105) — number of vertices in the tree.
Each of the next n lines contains 3 numbers v, l, r (0 ≤ v ≤ 109) — 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 is set instead. Note that different vertices of the tree may contain the same values.
Print number of times when search algorithm will fail.
3
15 -1 -1
10 1 3
5 -1 -1
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
1
In the example the root of the tree in vertex 2. Search of numbers 5 and 15 will return fail because on the first step algorithm will choose the subtree which doesn't contain numbers you are looking for.
题意:给出一颗二叉搜索树,不保证这棵树是正确的二叉搜索树,
那么按照二叉搜索树的搜索法则(小则往左,大则往右),就有可能找不到树上的某些节点
问找不到的节点有多少个
二叉搜索树,若根节点权值为10,那么左子树的权值范围为[-inf,9],右子树范围为[11,inf]
也就是说每个点的子节点可能的区间范围是确定的
若10有一个权值为a的左孩子,那么只有a的权值在[-inf,9]范围内,才能找到a
否则就找不到
右孩子同理
所以我们可以dfs统计满足要求的点的个数,
即若根节点权值为k,若左孩子权值在[l,k-1]之间,左孩子可以找到
若右孩子的权值在[k+1,r]之间,右孩子可以找到
最后 点的总数 减去 能找到的点的个数
注意:
1、累加可以找到的点时,累加这个权值的出现次数,
因为所有权值为这个的点,可能位于树的不同位置,但只要找到一个,所有权值为他的都可以找这一个
2、dfs(l[now],lk,min(v[now]-1,rk)); dfs(r[now],max(v[now]+1,lk),rk);
即注意dfs左子树时,区间右端点取大,dfs右子树时,区间左端点取小
为什么?因为点二叉搜索树是不正确的,到达位置错误的点时,要按错误的点来
为什么不直接累加不合法的?
累加合法的可以不用累加后清0,
累加不合法的可能是一个位置的不合法,但另一个位置的合法,
对于同一个权值,只要有一个位置合法,就能找到
#include<map> #include<cstdio> #include<algorithm> #define N 100001 using namespace std; int n,root,ans; int v[N],l[N],r[N]; bool h[N]; map<int,int>sum; int read() { int x=0,f=1;char c=getchar(); while(c<'0'||c>'9') { if(c=='-') f=-1;c=getchar(); } while(c>='0'&&c<='9') { x=x*10+c-'0'; c=getchar(); } return x; } void dfs(int now,int lk,int rk) { if(v[now]>=lk&&v[now]<=rk) ans+=sum[v[now]]; if(l[now]>0) dfs(l[now],lk,min(v[now]-1,rk)); if(r[now]>0) dfs(r[now],max(v[now]+1,lk),rk); } int main() { n=read(); for(int i=1;i<=n;i++) { scanf("%d%d%d",&v[i],&l[i],&r[i]); sum[v[i]]++; if(l[i]!=-1) h[l[i]]=true; if(r[i]!=-1) h[r[i]]=true; } for(int i=1;i<=n;i++) if(!h[i]) { root=i; break; } dfs(root,0,1e9); printf("%d",n-ans); }