超级码力初赛第二场 区间异或(初识线段树)

超级码力初赛-第二场-第二题-区间异或(初识线段树)

当初看到题目一脸懵逼,后来通过博客查看各大神的题解才知道这题需要用到线段树,经典模板题。

题目的意思我还是从别人的代码读懂的。

题目如下截图:

在这里插入图片描述

我来为小白讲解一下题目的意思:就是给定一个数组【1,2,3,4,5】,然后给定多个左右区间,一个左右区间用一个1X4数组表示,比如给的一个左右区间是【1,2,3,5】,即其中的左区间为12,右区间为35,左区间表示num数组中的第一个数到第二个数,即【1,2】,右区间同理,即【3,4,5】。

题目所说的区间区间对和就是左区间最大值2加上右区间最小值3,即 2+3 = 5。

把所有的和异或起来就能得到答案。

弄懂题目后,使用线段树就能够比较轻松地解题了,还要注意题目第一个值下标为1,即num[0]没有值。

解答:
//线段树的结点
class Node{
    public int l;   //区间最左边下标
    public int r;   //区间最右边下标
    
    public int max; //区间最大值
    public int min; //区间最小值
    
    public Node left_node; //区间左节点
    public Node right_node; //区间右节点
}
//num从下标1开始。
public int Intervalxor(int[] num, List<List<Integer>> ask) {
    Node root = new Node();
    //构建线段树
    build_tree(num,1,num.length,root);
    int result = 0;
    for(List<Integer> list : ask) {
        //结果异或左区间最大值加右区间最小值
        result ^= getMax(root,list.get(0),list.get(1)) + getMin(root,list.get(2),list.get(3));
    }
    return result;
}

//递归构建线段树
private void build_tree(int[] num, int l, int r,Node k) {
    k.l = l;
    k.r = r;
    if(l == r) {
        k.max = num[l - 1];
        k.min = num[l - 1];
        return;
    }
    k.left_node = new Node();
    k.right_node = new Node();
    int mid = (l + r) >> 1;
    build_tree(num,l,mid,k.left_node);
    build_tree(num,mid + 1,r,k.right_node);
    k.max = Math.max(k.left_node.max, k.right_node.max);
    k.min = Math.min(k.left_node.min, k.right_node.min);
}

//当区间只有一个元素时,返回该元素,否则返回其左区间和右区间中元素的最大值的较大值
private int getMax(Node k,int l,int r) {
    if(k.l == l && k.r == r) {
        return k.max;
    }
    int mid = (k.l + k.r) >> 1;
    if(r <= mid)
        return getMax(k.left_node,l,r);
    else if(l > mid)
        return getMax(k.right_node,l,r);
    else
        return Math.max(getMax(k.left_node,l,mid), getMax(k.right_node,mid + 1,r));
}
//当区间只有一个元素时,返回该元素,否则返回其左区间和右区间中元素的最小值的较小值
private int getMin(Node k,int l,int r) {
    if(k.l == l && k.r == r) {
        return k.min;
    }
    int mid = (k.l + k.r) >> 1;
    if(r <= mid)
        return getMin(k.left_node,l,r);
    else if(l > mid)
        return getMin(k.right_node,l,r);
    else
        return Math.min(getMin(k.left_node,l,mid), getMin(k.right_node,mid + 1,r));
}
_node,l,r);
    else
        return Math.min(getMin(k.left_node,l,mid), getMin(k.right_node,mid + 1,r));
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值