Submission #1308628

#TimeUsernameProblemLanguageResultExecution timeMemory
1308628orzorzorzTeams (IOI15_teams)C++20
0 / 100
1096 ms379120 KiB
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

const int MAXN = 500005;

// --- Persistent Segment Tree ---
struct Node {
    int count;
    Node *left, *right;
    
    Node(int count, Node *left, Node *right) : count(count), left(left), right(right) {}
};

Node* null;
Node* roots[MAXN]; 

// Build an empty tree
Node* build(int l, int r) {
    if (l == r) return new Node(0, null, null);
    int mid = l + (r - l) / 2;
    return new Node(0, build(l, mid), build(mid + 1, r));
}

// Update the tree (Add 1 at position p)
Node* update(Node* node, int l, int r, int p) {
    if (l == r) return new Node(node->count + 1, null, null);
    int mid = l + (r - l) / 2;
    if (p <= mid) return new Node(node->count + 1, update(node->left, l, mid, p), node->right);
    else return new Node(node->count + 1, node->left, update(node->right, mid + 1, r, p));
}

// Standard Query: Count in range [ql, qr] for a specific version
int query(Node* node, int l, int r, int ql, int qr) {
    if (ql > r || qr < l) return 0;
    if (ql <= l && r <= qr) return node->count;
    int mid = l + (r - l) / 2;
    return query(node->left, l, mid, ql, qr) + query(node->right, mid + 1, r, ql, qr);
}

// --- Critical Helper Function ---
// Find smallest index 'x' (in range of A-values) such that:
// Count of students with A <= x AND B in [yl, yr] >= k
int search_tree(Node* node_l, Node* node_r, int l, int r, int yl, int yr, int k) {
    // If total students in this full node range [yl, yr] < k, we can't find such x here
    // Note: This logic is slightly different. We are searching for 'x' (time/version),
    // but the tree is built on B-values. 
    // Actually, to search 'x' efficiently, we usually just Binary Search on the versions.
    // However, O(log^2 N) is acceptable. 
    // A strict O(log N) requires a different tree structure (Tree of B values, nodes store A).
    // But for IOI Teams, simple Binary Search on the answer 'x' is standard and passes.
    
    // We will implement Binary Search in the 'solve' function for clarity and safety.
    return 0; 
}

int N;
vector<int> adj[MAXN];

// Wrapper to count students with A <= x AND B in [y1, y2]
int count_students(int x, int y1, int y2) {
    if (y1 > y2) return 0;
    return query(roots[x], 1, N, y1, y2);
}

// Initial Setup
void init(int n, int A[], int B[]) {
    N = n;
    null = new Node(0, nullptr, nullptr);
    null->left = null->right = null;
    roots[0] = build(1, N);

    for (int i = 0; i < N; i++) {
        adj[A[i]].push_back(B[i]);
    }

    for (int i = 1; i <= N; i++) {
        roots[i] = roots[i-1];
        for (int b : adj[i]) {
            roots[i] = update(roots[i], 1, N, b);
        }
    }
}

// DP State
int dp[MAXN]; // Stores the "slack" (available - used)
int K_sorted[MAXN];

// Binary Search to find the split point between index i and j in the stack
// We want to find the coordinate 'x' where the transition from i equals transition from j
int find_split(int i, int j) {
    // We want smallest x such that:
    // count(x, K[i]+1, K[j]) >= dp[j] - dp[i]
    // where K[i] < K[j].
    
    int target = dp[j] - dp[i];
    int l = K_sorted[j], r = N + 1; // Range of possible A-values
    
    while (l < r) {
        int mid = l + (r - l) / 2;
        if (count_students(mid, K_sorted[i] + 1, K_sorted[j]) >= target) {
            r = mid;
        } else {
            l = mid + 1;
        }
    }
    return l;
}

int can(int M, int K[]) {
    // 1. Sort Groups
    for(int i=0; i<M; i++) K_sorted[i] = K[i];
    sort(K_sorted, K_sorted + M);
    
    // 2. Setup Stack
    // Stack stores indices of K_sorted
    vector<int> st; 
    
    // Use a dummy base case
    // We treat index -1 as having K=0, dp=0
    // But to avoid negative indices, let's manually handle the first element logic
    // or just assume implicit base.
    
    // Let's use clean iteration.
    // DP definition: dp[i] = max students remaining after satisfying groups 0...i
    // dp[i] = min_{j < i} ( dp[j] + count(K[i], K[j]+1, K[i]) ) - K[i]
    
    // Re-mapped logic to match standard variables:
    // We actually just compute values on the fly.
    
    st.clear();
    // Dummy element representing K=0, dp=0
    // We can't push a real index, so we handle the first step separately 
    // or insert a dummy into K_sorted? 
    // Inserting dummy is safer.
    
    vector<int> k_real;
    k_real.push_back(0);
    for(int i=0; i<M; i++) k_real.push_back(K_sorted[i]);
    
    // Reset DP array (only need size M+1)
    // Note: In global scope, dp is size MAXN, but here we index by 0..M
    // We'll use a local vector or reuse the global one carefully.
    
    vector<int> local_dp(M + 1, 0); 
    st.push_back(0); // Index 0 is the dummy (K=0, dp=0)
    
    for (int i = 1; i <= M; i++) {
        int k = k_real[i];
        
        // Stack Maintenance
        while (st.size() > 1) {
            int j = st.back();          // Top
            int l = st[st.size() - 2];  // Second Top
            
            // Check if 'j' is redundant.
            // It is redundant if the split point between l and j is >= split point between j and i
            // Or simpler: find split point between l and j. If that split is > k, j is useless?
            // Correct Logic:
            // The split point is where the "influence" of l ends and j begins.
            // If that split point is to the right of 'k', then for current 'k', l is strictly better/same as j.
            
            int split = find_split(l, j); // Uses global K_sorted logic, need to adapt to k_real
            // Careful with variable mapping. Let's fix find_split to take direct K values or indices into k_real.
            
            // Inline Find Split for indices l and j in k_real:
            int target = local_dp[j] - local_dp[l];
            int low = k_real[j], high = N + 1;
            int split_pos = N + 1;
            while(low < high) {
                int mid = low + (high - low)/2;
                if (count_students(mid, k_real[l] + 1, k_real[j]) >= target) {
                    split_pos = mid;
                    high = mid;
                } else {
                    low = mid + 1;
                }
            }
            
            if (split_pos <= k) {
                st.pop_back();
            } else {
                break;
            }
        }
        
        int j = st.back();
        // Calculate DP[i]
        // dp[i] = dp[j] + count(k, K[j]+1, k) - k
        int valid_cnt = count_students(k, k_real[j] + 1, k);
        local_dp[i] = local_dp[j] + valid_cnt - k;
        
        if (local_dp[i] < 0) return 0; // Impossible
        
        st.push_back(i);
    }

    return 1;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...