import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 *   public TreeNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

public class Solution {
    // 封装要获得的信息
    public class Info {
        public int max;
        public int min;
        public boolean isBST;

        public Info() {
            this.max = Integer.MAX_VALUE;
            this.min = Integer.MIN_VALUE;
            this.isBST = true;
        }

        public Info(int max, int min, boolean isBST) {
            this.max = max;
            this.min = min;
            this.isBST = isBST;
        }
    }
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param root TreeNode类
     * @return bool布尔型
     */
    public boolean isValidBST (TreeNode root) {
        // write code here

        // 1.我要干什么:
        //        我要确定以root为根结点的子树是否是二叉搜索树

        // 2.我需要什么信息:
        //      获知【左子树】的【最大节点值】以及【是否二叉搜索树】
        //      获知【右子树】的【最小节点值】以及【是否二叉搜索树】
        //      综上所述,我需要左右子树的【最大和最小节点值】与【是否二叉搜索树】

        // 3.我如何利用两个子树的信息加工出来我的信息:
        //      若两棵子树均是二叉搜索树,且右 > root > 左,则true

        return process(root).isBST;
    }

    public Info process (TreeNode root) {
        // 递归出口
        if (root == null) {
            return new Info();
        }

        Info leftInfo = process(root.left);
        Info rightInfo = process(root.right);

        // 计算左右子树的真实最大值和最小值(如果为空,则置为root的值)
        int trueLeftMax = leftInfo.max != Integer.MAX_VALUE ? leftInfo.max : root.val;
        int trueLeftMin = leftInfo.min != Integer.MIN_VALUE ? leftInfo.min : root.val;
        int trueRightMax = rightInfo.max != Integer.MAX_VALUE ? rightInfo.max : root.val;
        int trueRightMin = rightInfo.min != Integer.MIN_VALUE ? rightInfo.min : root.val;
        // 计算本子树的最大值和最小值
        int myMax = Math.max(root.val, Math.max(trueLeftMax, trueRightMax));
        int myMin = Math.min(root.val, Math.min(trueLeftMin, trueRightMin));

        if (leftInfo.isBST == false || rightInfo.isBST == false) {
            // 两棵子树只要有一个不是二叉搜索树,直接false
            return new Info(myMax, myMin, false);
        }
        // 两棵子树都是二叉搜索树
        // 注意!这里的等号是为了让子节点为null时(即左右最大或最小结点的值与本结点值相同)通过判断
        if (trueLeftMax <= root.val && root.val <= trueRightMin) {
            // 且满足右min > root > 左max,则true
            return new Info(myMax, myMin, true);
        }
        return new Info(myMax, myMin, false);
    }
}