CodeForces 1042D 解题

题目大意:

给你N个数字,和一个数字t,求满足l<=r,a[l] + a[l+1] + …… + a[r] < t 的(l,r)对数。

 

思路

首先考虑a[l] + a[l+1] + …… + a[r]应该用sum[r] - sum[l - 1]直接求得,那么对于每一个sum[i],我们要求的就是sum[j] > sum[i] - t (1 <= j <= i - 1) 的j的个数。想到的是每次处理完sum[i],都要把sum[i]添加到数据结构中,还要方便查找小于某一数字的节点个数。前者添加最优的是链表,后者查找最优的有序数组,综合一下就是树了。我在这里用的是二叉平衡数,做完之后想了一下,感觉可能用优先队列那样的树可能更合适,写起来更方便。

 

代码实现

i 从 1 到 n

对于当前 i,查找树中的大于sum[i] - t的个数,这样就求出了满足sum[i] - sum[j] < t 的j的个数。

找完之后,将sum[i]添加到树中。

这里有个问题,平衡二叉树一般不插入同值节点,但是题目里有可能,所以要处理一下。节点应该要保存的信息有:节点值,节点值的个数(为了解决同值问题),左子树所有节点的节点值个数加上当前节点值个数的和(有点绕口,理解起来就是小于等于当前节点值的sum[j]的j的个数,不过这里有同值,节点信息里多了个值的个数,说起来绕口)

丑陋的代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;

public class Main1042D {

    static class Node {

        public int height;
        public long value;
        public Node parent;
        public Node leftSon;
        public Node rightSon;
        public int valueCount;
        public int count;

        public Node(long v) {
            value = v;
            height = 1;
            parent = null;
            leftSon = null;
            rightSon = null;
            count = 1;
            valueCount = 1;
        }

        public void calculateCount() {
            int count = 0;
            if (null != leftSon)
                count += leftSon.count;
            if (null != rightSon)
                count += rightSon.count;
            this.count = count + valueCount;
        }

        public void calculatorHeight() {
            int leftHeight = 0;
            int rightHeight = 0;
            if (null != leftSon)
                leftHeight = leftSon.height;
            if (null != rightSon)
                rightHeight = rightSon.height;
            this.height = Math.max(leftHeight, rightHeight) + 1;
        }
    }

    static Node root;

    public static void main(String[] args) throws IOException {

        StreamTokenizer streamTokenizer = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));

        streamTokenizer.nextToken();
        int n = (int) streamTokenizer.nval;
        streamTokenizer.nextToken();
        long t = (long) streamTokenizer.nval;

        long x;
        long count = 0;
        root = new Node(0);
        Node temp;
        long ans = 0;
        for (int i = 0; i < n; i++) {
            streamTokenizer.nextToken();
            x = (long) streamTokenizer.nval;
            count += x;
            temp = new Node(count);
            ans += find(count - t);
            addNode(root, temp);
        }

        System.out.println(ans);
    }

    public static void addNode(Node cur, Node node) {
        if (cur.value < node.value) {
            if (null == cur.rightSon) {
                node.parent = cur;
                cur.rightSon = node;
            } else
                addNode(cur.rightSon, node);
        }
        else if (cur.value > node.value) {
            if (null == cur.leftSon) {
                node.parent = cur;
                cur.leftSon = node;
            }
            else
                addNode(cur.leftSon, node);
        } else {
            cur.valueCount++;
            cur.count++;
        }
        int leftHeight = 0;
        int rightHeight = 0;
        int leftHeight2 = 0;
        int rightHeight2 = 0;
        if (null != cur.leftSon)
            leftHeight = cur.leftSon.height;
        if (null != cur.rightSon)
            rightHeight = cur.rightSon.height;
        if (leftHeight > rightHeight + 1) { //左边高
            if (null != cur.leftSon.leftSon)
                leftHeight2 = cur.leftSon.leftSon.height;
            if (null != cur.leftSon.rightSon)
                rightHeight2 = cur.leftSon.rightSon.height;
            if (leftHeight2 > rightHeight2) //左左
                rightTranslate(cur);
            else { //左右
                leftTranslate(cur.leftSon);
                rightTranslate(cur);
            }
        }
        else if (rightHeight > leftHeight + 1) {//右边高
            if (null != cur.rightSon.leftSon)
                leftHeight2 = cur.rightSon.leftSon.height;
            if (null != cur.rightSon.rightSon)
                rightHeight2 = cur.rightSon.rightSon.height;
            if (leftHeight2 > rightHeight2) { //右左
                rightTranslate(cur.rightSon);
                leftTranslate(cur);
            }
            else //右右
                leftTranslate(cur);
        }
        else {
            cur.height = Math.max(leftHeight, rightHeight) + 1;
            cur.calculateCount();
        }
    }

    public static void leftTranslate(Node node) {
        Node rightSon = node.rightSon;
        node.rightSon = rightSon.leftSon;
        if (null != node.rightSon)
            node.rightSon.parent = node;
        rightSon.leftSon = node;
        if (null == node.parent)
            root = rightSon;
        else if (node.parent.leftSon == node)
            node.parent.leftSon = rightSon;
        else
            node.parent.rightSon = rightSon;
        rightSon.parent = node.parent;
        node.parent = rightSon;
        node.calculateCount();
        rightSon.calculateCount();
        node.calculatorHeight();
        rightSon.calculatorHeight();
    }

    public static void rightTranslate(Node node) {
        Node leftSon = node.leftSon;
        node.leftSon = leftSon.rightSon;
        if (null != node.leftSon)
            node.leftSon.parent = node;
        leftSon.rightSon = node;
        if (null == node.parent)
            root = leftSon;
        else if (node.parent.leftSon == node)
            node.parent.leftSon = leftSon;
        else
            node.parent.rightSon = leftSon;
        leftSon.parent = node.parent;
        node.parent = leftSon;
        node.calculateCount();
        leftSon.calculateCount();
        node.calculatorHeight();
        leftSon.calculatorHeight();
    }

    public static int find(long v) {
        Node node = root;
        int result = 0;
        while (null != node) {
            if (node.value > v) {
                if (null != node.rightSon)
                    result += node.rightSon.count;
                result += node.valueCount;
                node = node.leftSon;
            } else
                node = node.rightSon;
        }
        return result;
    }
}

写的不好,欢迎指教23333

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值