牛客假日团队赛3 - Seating (线段树)

知识共享许可协议 版权声明:署名,允许他人基于本文进行创作,且必须基于与原先许可协议相同的许可协议分发本文 (Creative Commons

链接:https://ac.nowcoder.com/acm/contest/945/I
来源:牛客网

题目描述

To earn some extra money, the cows have opened a restaurant in their barn specializing in milkshakes. The restaurant has N seats (1 <= N <= 500,000) in a row. Initially, they are all empty.
Throughout the day, there are M different events that happen in sequence at the restaurant (1 <= M <= 300,000). The two types of events that can happen are:

  1. A party of size p arrives (1 <= p <= N). Bessie wants to seat the party in a contiguous block of p empty seats. If this is possible, she does so in the lowest position possible in the list of seats. If it is impossible, the party is turned away.
  2. A range [a,b] is given (1 <= a <= b <= N), and everybody in that range of seats leaves. Please help Bessie count the total number of parties that are turned away over the course of the day.

输入描述:

  • Line 1: Two space-separated integers, N and M.

  • Lines 2…M+1: Each line describes a single event. It is either a
    line of the form “A p” (meaning a party of size p arrives) or
    “L a b” (meaning that all cows in the range [a, b] leave).

输出描述:

  • Line 1: The number of parties that are turned away.

输入

10 4
A 6
L 2 4
A 5
A 2

输出

1

INPUT DETAILS:

There are 10 seats, and 4 events. First, a party of 6 cows arrives. Then
all cows in seats 2…4 depart. Next, a party of 5 arrives, followed by a
party of 2.

OUTPUT DETAILS:

Party #3 is turned away. All other parties are seated.

解题思路

这题做了我半天。。。。
想起大一的时候小学期做过同样的题目,不过那个时候得到数据规模是很小的,所以当时的我是暴力做的。
拿到这个题,第一个想到线段树,去记录区间可用的seat有多少个。这么做还不够,还需要能找到安排时最左的满足条件的坐标。
那线段树就需要再多记录两个元素。一个是从左往右数空闲位置的个数,另一个是从右往左树空闲位置的个数。

说的再多,也不如代码清楚:

AC Code:

/*
 * Copyright (c) 2019 Ng Kimbing, HNU, All rights reserved. May not be used, modified, or copied without permission.
 * @Author: Ng Kimbing, HNU.
 * @LastModified:2019-06-25 T 16:16:48.826 +08:00
 */
package ACMProblems.QianDaoTi;

import static ACMProblems.ACMIO.*;

public class Main {
    private static final int maxN = 500000 + 10;
    private static final int REMOVE_ALL = 1;
    private static final int PLACE = 2;

    static class Node {
        int numFromLeft;
        int numFromRight;
        int value;
        int lazyType;

        public Node(int numFromLeft, int numFromRight, int value, int lazyType) {
            this.numFromLeft = numFromLeft;
            this.numFromRight = numFromRight;
            this.value = value;
            this.lazyType = lazyType;
        }

        Node() {}
    }

    private static Node[] nodes = new Node[maxN * 4];

    private static void pushUp(int l, int r, int curr) {
        updateLeftRight(l, r, curr);
        // considering merge sort
        nodes[curr].value = Math.max(
                Math.max(nodes[curr << 1].value, nodes[curr << 1 | 1].value),
                nodes[curr << 1].numFromRight + nodes[curr << 1 | 1].numFromLeft
        );
    }

    private static void updateLeftRight(int l, int r, int curr) {
        int mid = (l + r) >> 1;
        nodes[curr].numFromLeft = (nodes[curr << 1].value == (mid - l + 1)) ?
                nodes[curr << 1].value + nodes[curr << 1 | 1].numFromLeft :
                nodes[curr << 1].numFromLeft;
        nodes[curr].numFromRight = (nodes[curr << 1 | 1].value == (r - mid)) ?
                nodes[curr << 1 | 1].value + nodes[curr << 1].numFromRight :
                nodes[curr << 1 | 1].numFromRight;
    }

    private static void pushDown(int l, int r, int curr) {
        nodes[curr << 1].lazyType = nodes[curr << 1 | 1].lazyType = nodes[curr].lazyType;
        int m = (l + r) >> 1;
        if (nodes[curr].lazyType == REMOVE_ALL) {
            nodes[curr << 1].numFromLeft = nodes[curr << 1].numFromRight = nodes[curr << 1].value = m - l + 1;
            nodes[curr << 1 | 1].numFromLeft = nodes[curr << 1 | 1].numFromRight = nodes[curr << 1 | 1].value = r - m;
        } else if (nodes[curr].lazyType == PLACE) {
            nodes[curr << 1].numFromLeft = nodes[curr << 1].numFromRight = nodes[curr << 1].value = 0;
            nodes[curr << 1 | 1].numFromLeft = nodes[curr << 1 | 1].numFromRight = nodes[curr << 1 | 1].value = 0;
        }
        nodes[curr].lazyType = 0;
    }

    private static void build(int left, int right, int curr) {
        if (left == right) {
            if (nodes[curr] == null) {
                nodes[curr] = new Node(1, 1, 1, 0);
                return;
            }
            nodes[curr].numFromLeft = nodes[curr].numFromRight = nodes[curr].value = 1;
            return;
        }
        int mid = (left + right) >> 1;
        build(left, mid, curr << 1);
        build(mid + 1, right, curr << 1 | 1);
        nodes[curr] = new Node();
        pushUp(left, right, curr);
    }

    private static void update(int targetL, int targetR, int operationType, int l, int r, int curr) {
        if (nodes[curr].lazyType != 0 && curr * 2 + 1 < nodes.length)
            pushDown(l, r, curr);
        // the whole interval
        if (targetL <= l && r <= targetR) {
            if (operationType == REMOVE_ALL)
                nodes[curr].numFromLeft = nodes[curr].numFromRight = nodes[curr].value = r - l + 1;
            if (operationType == PLACE)
                nodes[curr].numFromLeft = nodes[curr].numFromRight = nodes[curr].value = 0;
            nodes[curr].lazyType = operationType;
            return;
        }
        int mid = (l + r) >> 1;
        if (targetL <= mid) update(targetL, targetR, operationType, l, mid, curr << 1);
        if (targetR > mid) update(targetL, targetR, operationType, mid + 1, r, curr << 1 | 1);
        pushUp(l, r, curr);
    }

    private static int query(int requiredSeats, int left, int right, int curr) {
        if (nodes[curr].lazyType != 0 && curr * 2 + 1 < nodes.length)
            pushDown(left, right, curr);
        if (left == right)
            return left;
        int m = (left + right) >> 1;
        // There are enough seats in the left part
        if (nodes[curr << 1].value >= requiredSeats)
            return query(requiredSeats, left, m, curr << 1);
            // Cross two sub-intervals
        else if (nodes[curr << 1].numFromRight + nodes[curr << 1 | 1].numFromLeft >= requiredSeats)
            return m - nodes[curr << 1].numFromRight + 1;
            // try to look for it in the right part
        else
            return query(requiredSeats, m + 1, right, curr << 1 | 1);
    }

    public static void main(String[] args) throws Exception {
        setStream(System.in);
        for (int i = 0; i < nodes.length; ++i)
            nodes[i] = new Node();
        int n = nextInt();
        int m = nextInt();
        build(1, n, 1);
        int num = 0;
        for (int i = 1; i <= m; i++) {
            char cmd = nextChar();
            if (cmd == 'A') {
                int x = nextInt();
                if (nodes[1].value >= x) {
                    int ans = query(x, 1, n, 1);
                    update(ans, ans + x - 1, PLACE, 1, n, 1);
                } else num++;
            } else {
                int l = nextInt();
                int r = nextInt();
                update(l, r, REMOVE_ALL, 1, n, 1);
            }
        }
        System.out.println(num);
    }
}



这题很奇葩,上述代码在OJ上交就是超时,(但实际上并不会超时)应该是OJ的问题
因此我对OJ进行了测试:

题目给的是两秒钟的时间, 提交如下代码:

public class Main{
    static Main[]mains= new Main[(int)(500000*4)];
    public static void main(String[]args)throws Exception{
        long start = System.currentTimeMillis();
        for(int i = 0; i < 2000000; ++i){
            mains[i] = new Main();
            long end = System.currentTimeMillis();
            if(i % 10000 == 0)
                System.out.println(i + ", time duration: "+(end - start));
        }
        long end = System.currentTimeMillis();
        System.out.println((end-start));
    }
}

输出结果的最后几行为
在这里插入图片描述
判题结果为:
在这里插入图片描述
有整整1.5秒的时间并不能得到利用,跑了半秒就停了。。

(怀疑可能和内存之类的方面有关, 因为当将循环内的new语句改为简单的加法,增大循环次数,可以跑到两秒,但如上的代码,怎么也超不过半秒就无法继续进行。)

OJ可能对JAVA 有什么偏见
因此改成了C++版本就顺利AC了

C++ AC Code:

	#include<bits/stdc++.h>
	using namespace std;
     const int maxn = 500000 + 10;
    //    static const int maxn = 15;
     const int REMOVE_ALL = 1;
     const int PLACE = 2;
 
    const int mi = maxn*3;
    class Node {
        public:
        int numFromLeft;
        int numFromRight;
        int value;
        int lazyType;
 
        Node(int numFromLeft, int numFromRight, int value, int lazyType) {
            this->numFromLeft = numFromLeft;
            this->numFromRight = numFromRight;
            this->value = value;
            this->lazyType = lazyType;
        }
 
        Node() {}
    };
 
     Node nodes[maxn * 4];
//    static {
//        for (int i = 0; i < nodes.length; ++i)
//            nodes[i] = new Node();
//    }
     void updateLeftRight(int l, int r, int curr) {
        int mid = (l + r) >> 1;
            nodes[curr].numFromLeft = (nodes[curr << 1].value == (mid - l + 1)) ?
                    nodes[curr << 1].value + nodes[curr << 1 | 1].numFromLeft :
                    nodes[curr << 1].numFromLeft;
            nodes[curr].numFromRight = (nodes[curr << 1 | 1].value == (r - mid)) ?
                    nodes[curr << 1 | 1].value + nodes[curr << 1].numFromRight :
                    nodes[curr << 1 | 1].numFromRight;
       
    }
     void pushUp(int l, int r, int curr) {
        updateLeftRight(l, r, curr);
        // considering merge sort
        
        nodes[curr].value = max(
                max(nodes[curr << 1].value, nodes[curr << 1 | 1].value),
                nodes[curr << 1].numFromRight + nodes[curr << 1 | 1].numFromLeft
        );
    }
 
     void pushDown(int l, int r, int curr) {
     	
            nodes[curr << 1].lazyType = nodes[curr << 1 | 1].lazyType = nodes[curr].lazyType;
            int m = (l + r) >> 1;
            if (nodes[curr].lazyType == REMOVE_ALL) {
                nodes[curr << 1].numFromLeft = nodes[curr << 1].numFromRight = nodes[curr << 1].value = m - l + 1;
                nodes[curr << 1 | 1].numFromLeft = nodes[curr << 1 | 1].numFromRight = nodes[curr << 1 | 1].value = r - m;
            } else if (nodes[curr].lazyType == PLACE) {
                nodes[curr << 1].numFromLeft = nodes[curr << 1].numFromRight = nodes[curr << 1].value = 0;
                nodes[curr << 1 | 1].numFromLeft = nodes[curr << 1 | 1].numFromRight = nodes[curr << 1 | 1].value = 0;
            }
         
        nodes[curr].lazyType = 0;
    }
 
     void build(int left, int right, int curr) {
        if (left == right) {
            nodes[curr].numFromLeft = nodes[curr].numFromRight = nodes[curr].value = 1;
            return;
        }
        int mid = (left + right) >> 1;
        build(left, mid, curr << 1);
        build(mid + 1, right, curr << 1 | 1);
        pushUp(left, right, curr);
    }
 
     void update(int targetL, int targetR, int operationType, int l, int r, int curr) {
        if (nodes[curr].lazyType != 0 && curr * 2 + 1 < mi)
            pushDown(l, r, curr);
        // the whole interval
        if (targetL <= l && r <= targetR) {
            if (operationType == REMOVE_ALL)
                nodes[curr].numFromLeft = nodes[curr].numFromRight = nodes[curr].value = r - l + 1;
            if (operationType == PLACE)
                nodes[curr].numFromLeft = nodes[curr].numFromRight = nodes[curr].value = 0;
            nodes[curr].lazyType = operationType;
            return;
        }
        int mid = (l + r) >> 1;
        if (targetL <= mid) update(targetL, targetR, operationType, l, mid, curr << 1);
        if (targetR > mid) update(targetL, targetR, operationType, mid + 1, r, curr << 1 | 1);
        pushUp(l, r, curr);
    }
 
    int query(int requiredSeats, int left, int right, int curr) {
        if (nodes[curr].lazyType != 0)
            pushDown(left, right, curr);
        if (left == right)
            return left;
        int m = (left + right) >> 1;
        // There are enough seats in the left part
        if (nodes[curr << 1].value >= requiredSeats)
            return query(requiredSeats, left, m, curr << 1);
            // Cross two sub-intervals
        else if (nodes[curr << 1].numFromRight + nodes[curr << 1 | 1].numFromLeft >= requiredSeats)
            return m - nodes[curr << 1].numFromRight + 1;
            // try to look for it in the right part
        else
            return query(requiredSeats, m + 1, right, curr << 1 | 1);
    }
 
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(0);
        cout.tie(0);
        int n, m;
//        long start = System.currentTimeMillis();
//        for (int i = 0; i < nodes.length; ++i)
//            nodes[i] = new Node();
//        long end = System.currentTimeMillis();
//        System.out.println((end - start));
//        System.exit(-1);
        cin >> n >> m;
        build(1, n, 1);
//        int foo =(int) (Math.log(n)/Math.log(2) + 1) * 2;
//        System.out.println(foo);
//        System.exit(0);
        int num = 0;
        for (int i = 1; i <= m; i++) {
            char cmd;
            cin >> cmd;
            if (cmd == 'A') {
                int x;
                cin >> x;
                if (nodes[1].value >= x) {
                    int ans = query(x, 1, n, 1);
                    update(ans, ans + x - 1, PLACE, 1, n, 1);
                } else num++;
            } else {
                int l, r;
                cin >> l >> r;
                update(l, r, REMOVE_ALL, 1, n, 1);
            }
        }
        cout << num << endl;
    }

猜你喜欢

转载自blog.csdn.net/weixin_44090305/article/details/93629219
今日推荐