Submission #1150213

#TimeUsernameProblemLanguageResultExecution timeMemory
1150213lancethedragontrainerRMQ (NOI17_rmq)Java
100 / 100
659 ms62104 KiB
import java.io.*;
import java.util.*;

public class rmq {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
        StringTokenizer st = new StringTokenizer(br.readLine());
        int N = Integer.parseInt(st.nextToken());
        int Q = Integer.parseInt(st.nextToken());

        // For each tag A, record the allowed interval where it must appear if used in a query.
        int[] allowedL = new int[N];
        int[] allowedR = new int[N];
        Arrays.fill(allowedL, 0);
        Arrays.fill(allowedR, N - 1);
        boolean[] hasQuery = new boolean[N];

        // Generate events for a sweep-line to compute LB[].
        // Each query [L, R, A] gives an add event at L and (if R+1 < N) a remove event at R+1.
        int totalEvents = 2 * Q;
        Event[] events = new Event[totalEvents];
        int eventCount = 0;

        // Process each query.
        for (int i = 0; i < Q; i++) {
            st = new StringTokenizer(br.readLine());
            int L = Integer.parseInt(st.nextToken());
            int R = Integer.parseInt(st.nextToken());
            int A = Integer.parseInt(st.nextToken());

            // Update allowed interval for tag A.
            allowedL[A] = Math.max(allowedL[A], L);
            allowedR[A] = Math.min(allowedR[A], R);
            hasQuery[A] = true;

            events[eventCount++] = new Event(L, A, true);
            if (R + 1 < N) {
                events[eventCount++] = new Event(R + 1, A, false);
            }
        }

        // Sort events by index (and add events before remove events when indices are equal).
        Arrays.sort(events, 0, eventCount);

        // Compute LB[i] for positions i = 0..N-1 using a sweep-line.
        // LB[i] is the maximum A among all queries covering position i.
        int[] LB = new int[N];
        TreeMap<Integer, Integer> active = new TreeMap<>();
        int idxEvent = 0;
        for (int i = 0; i < N; i++) {
            while (idxEvent < eventCount && events[idxEvent].index == i) {
                Event e = events[idxEvent];
                if (e.add) {
                    active.put(e.val, active.getOrDefault(e.val, 0) + 1);
                } else {
                    int cnt = active.get(e.val);
                    if (cnt == 1) {
                        active.remove(e.val);
                    } else {
                        active.put(e.val, cnt - 1);
                    }
                }
                idxEvent++;
            }
            LB[i] = active.isEmpty() ? 0 : active.lastKey();
        }

        // Build candidate lists for each value v: positions i with LB[i] == v.
        ArrayList<ArrayList<Integer>> candidates = new ArrayList<>(N);
        for (int v = 0; v < N; v++) {
            candidates.add(new ArrayList<>());
        }
        for (int i = 0; i < N; i++) {
            candidates.get(LB[i]).add(i);
        }

        // For each tag A that appears in a query, assign it to a candidate position
        // in the allowed interval [allowedL[A], allowedR[A]].
        int[] designatedPos = new int[N]; // designatedPos[A] holds the position chosen for tag A.
        Arrays.fill(designatedPos, -1);
        boolean possible = true;
        for (int A = 0; A < N; A++) {
            if (hasQuery[A]) {
                ArrayList<Integer> list = candidates.get(A);
                // Binary search in list for the smallest index >= allowedL[A]
                int pos = Collections.binarySearch(list, allowedL[A]);
                if (pos < 0) {
                    pos = -pos - 1;
                }
                if (pos >= list.size() || list.get(pos) > allowedR[A]) {
                    possible = false;
                    break;
                }
                designatedPos[A] = list.get(pos);
            }
        }

        if (!possible) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < N; i++) {
                sb.append("-1 ");
            }
            out.println(sb.toString().trim());
            out.close();
            return;
        }

        // Create the result array and assign the designated tags.
        int[] result = new int[N];
        Arrays.fill(result, -1);
        boolean[] usedTag = new boolean[N];
        for (int A = 0; A < N; A++) {
            if (hasQuery[A]) {
                int pos = designatedPos[A];
                result[pos] = A;
                usedTag[A] = true;
            }
        }

        // For every unassigned position, assign an unused tag X such that X >= LB[i].
        TreeSet<Integer> availTag = new TreeSet<>();
        for (int tag = 0; tag < N; tag++) {
            if (!usedTag[tag]) {
                availTag.add(tag);
            }
        }
        for (int i = 0; i < N; i++) {
            if (result[i] == -1) {
                Integer tag = availTag.ceiling(LB[i]);
                if (tag == null) {
                    possible = false;
                    break;
                }
                result[i] = tag;
                availTag.remove(tag);
            }
        }

        if (!possible) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < N; i++) {
                sb.append("-1 ");
            }
            out.println(sb.toString().trim());
        } else {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < N; i++) {
                sb.append(result[i]);
                if (i < N - 1) {
                    sb.append(" ");
                }
            }
            out.println(sb.toString().trim());
        }
        out.close();
    }

    // Helper class for events used in the sweep-line.
    static class Event implements Comparable<Event> {
        int index, val;
        boolean add;

        public Event(int index, int val, boolean add) {
            this.index = index;
            this.val = val;
            this.add = add;
        }

        public int compareTo(Event other) {
            if (this.index != other.index) {
                return this.index - other.index;
            }
            // When indices are equal, add events come before remove events.
            if (this.add == other.add) {
                return 0;
            }
            return this.add ? -1 : 1;
        }
    }
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...