Submission #1289687

#TimeUsernameProblemLanguageResultExecution timeMemory
1289687SamueleVidPort Facility (JOI17_port_facility)C++20
0 / 100
96 ms131656 KiB
#include <stdio.h>
#include <vector>
#include <algorithm>
using namespace std;

typedef pair<int, int> pii;
#define SEGTREE_SIZE (1 << 21)
#define LOG 21

class UnionFind {
public:
    int parent[SEGTREE_SIZE * 2];
    int rank[SEGTREE_SIZE * 2];
    
    void init() {
        for (int i = 0; i < SEGTREE_SIZE * 2; i++) {
            parent[i] = i;
            rank[i] = 0;
        }
    }
    
    int find(int x) {
        if (x == parent[x]) return x;
        return parent[x] = find(parent[x]);
    }
    
    void unite(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) return;
        
        if (rank[x] > rank[y]) {
            parent[y] = x;
        } else {
            parent[x] = y;
            if (rank[x] == rank[y]) rank[y]++;
        }
    }
};

UnionFind uf;

// Aggiunge un vincolo tra due intervalli
void add_constraint(int interval_a, int interval_b, bool same_stack) {
    // Ogni intervallo ha due possibili posizioni: 
    // interval*2 = stack1, interval*2+1 = stack2
    
    if (same_stack) {
        // Stesso stack: (a0 <-> b0) e (a1 <-> b1)
        uf.unite(interval_a * 2, interval_b * 2);
        uf.unite(interval_a * 2 + 1, interval_b * 2 + 1);
    } else {
        // Stack diversi: (a0 <-> b1) e (a1 <-> b0)
        uf.unite(interval_a * 2, interval_b * 2 + 1);
        uf.unite(interval_a * 2 + 1, interval_b * 2);
    }
}

class IntervalSolver {
public:
    vector<pii> node_segments[1 << (LOG + 1)];  // Segmenti in ogni nodo
    bool is_valid;  // Se la soluzione è possibile
    
    void init() {
        is_valid = true;
        for (int i = 0; i < (1 << (LOG + 1)); i++) {
            node_segments[i].clear();
        }
    }
    
    // Aggiunge un intervallo al segment tree
    void add_interval(int start, int end) {
        int node = 1;
        int left = 0, right = (1 << LOG) - 1;
        
        while (true) {
            int mid = (left + right) / 2;
            
            if (end <= mid) {
                // Intervallo completamente a sinistra
                right = mid;
                node = node * 2;
            } else if (start >= mid + 1) {
                // Intervallo completamente a destra
                left = mid + 1;
                node = node * 2 + 1;
            } else {
                // Intervallo centrale (attraversa mid)
                node_segments[node].push_back(make_pair(start, end));
                break;
            }
        }
    }
    
    // Risolve i conflitti tra intervalli dello stesso nodo
    void solve_node_conflicts(int node, int left_bound, int right_bound) {
        if (node_segments[node].empty()) return;
        
        // Ordina gli intervalli per start point
        sort(node_segments[node].begin(), node_segments[node].end());
        
        vector<pii> non_nested, nested;
        int min_end = 1000000000;
        
        // Separa in non annidati e annidati
        for (int i = 0; i < node_segments[node].size(); i++) {
            if (node_segments[node][i].second < min_end) {
                min_end = node_segments[node][i].second;
                non_nested.push_back(node_segments[node][i]);
            } else {
                nested.push_back(node_segments[node][i]);
            }
        }
        
        // Verifica che gli intervalli annidati siano in ordine decrescente di end
        for (int i = 1; i < nested.size(); i++) {
            if (nested[i - 1].second < nested[i].second) {
                is_valid = false;
                return;
            }
        }
        
        // Aggiungi vincoli tra non_nested e nested
        int ptr = 0;
        for (int i = 0; i < non_nested.size(); i++) {
            while (ptr < nested.size() && nested[ptr].second < non_nested[i].second) {
                // Conflitto: devono avere stack diversi
                add_constraint(non_nested[i].first, nested[ptr].first, false);
                ptr++;
            }
            if (ptr > 0) ptr--;
        }
    }
    
    int temp_index[SEGTREE_SIZE];
    int prefix_sum[SEGTREE_SIZE];
    
    // Risolve conflitti tra nodo corrente e figlio sinistro
    void solve_left_child_conflicts(int node, int left_bound, int right_bound) {
        if (node_segments[node].empty() || node_segments[node * 2].empty()) return;
        
        int mid = (left_bound + right_bound) / 2;
        int left_size = mid - left_bound + 1;
        
        // Inizializza array temporanei
        fill(temp_index, temp_index + left_size, -1);
        fill(prefix_sum, prefix_sum + node_segments[node].size() + 1, 0);
        
        // Costruisci indice per mapping veloce
        for (int i = 0; i < node_segments[node].size(); i++) {
            int pos = node_segments[node][i].first - left_bound;
            if (pos < left_size) {
                temp_index[pos] = i;
            }
        }
        for (int i = 1; i < left_size; i++) {
            if (temp_index[i] == -1) {
                temp_index[i] = temp_index[i - 1];
            }
        }
        
        // Processa intervalli del figlio sinistro
        for (int i = 0; i < node_segments[node * 2].size(); i++) {
            int start_idx = node_segments[node * 2][i].first - left_bound;
            int end_idx = node_segments[node * 2][i].second - left_bound;
            
            if (start_idx < left_size && end_idx < left_size && 
                temp_index[start_idx] != -1 && temp_index[end_idx] != -1 &&
                temp_index[start_idx] < temp_index[end_idx]) {
                prefix_sum[temp_index[start_idx] + 1]++;
                prefix_sum[temp_index[end_idx]]--;
            }
        }
        
        // Aggiungi vincoli per conflitti diretti
        for (int i = 0; i < node_segments[node * 2].size(); i++) {
            int start_idx = node_segments[node * 2][i].first - left_bound;
            int end_idx = node_segments[node * 2][i].second - left_bound;
            
            if (start_idx < left_size && end_idx < left_size && 
                temp_index[start_idx] != -1 && temp_index[end_idx] != -1 &&
                temp_index[start_idx] < temp_index[end_idx]) {
                add_constraint(node_segments[node * 2][i].first, 
                             node_segments[node][temp_index[end_idx]].first, false);
            }
        }
        
        // Calcola prefix sum e aggiungi vincoli tra intervalli consecutivi
        for (int i = 1; i <= node_segments[node].size(); i++) {
            prefix_sum[i] += prefix_sum[i - 1];
        }
        for (int i = 0; i < (int)node_segments[node].size() - 1; i++) {
            if (prefix_sum[i] > 0) {
                add_constraint(node_segments[node][i].first, 
                             node_segments[node][i + 1].first, true);
            }
        }
    }
    
    // Risolve conflitti tra nodo corrente e figlio destro (simmetrico)
    void solve_right_child_conflicts(int node, int left_bound, int right_bound) {
        if (node_segments[node].empty() || node_segments[node * 2 + 1].empty()) return;
        
        int mid = (left_bound + right_bound) / 2;
        int right_start = mid + 1;
        int right_size = right_bound - right_start + 1;
        
        // Ordina gli intervalli per end point
        vector<pii> sorted_by_end = node_segments[node];
        for (int i = 0; i < sorted_by_end.size(); i++) {
            swap(sorted_by_end[i].first, sorted_by_end[i].second);
        }
        sort(sorted_by_end.begin(), sorted_by_end.end());
        for (int i = 0; i < sorted_by_end.size(); i++) {
            swap(sorted_by_end[i].first, sorted_by_end[i].second);
        }
        
        // Inizializza array temporanei
        fill(temp_index, temp_index + right_size, -1);
        fill(prefix_sum, prefix_sum + node_segments[node].size() + 1, 0);
        
        // Costruisci indice per end point
        for (int i = 0; i < sorted_by_end.size(); i++) {
            int pos = sorted_by_end[i].second - right_start;
            if (pos < right_size) {
                temp_index[pos] = i;
            }
        }
        for (int i = 1; i < right_size; i++) {
            if (temp_index[i] == -1) {
                temp_index[i] = temp_index[i - 1];
            }
        }
        
        // Processa intervalli del figlio destro
        for (int i = 0; i < node_segments[node * 2 + 1].size(); i++) {
            int start_idx = node_segments[node * 2 + 1][i].first - right_start;
            int end_idx = node_segments[node * 2 + 1][i].second - right_start;
            
            if (start_idx < right_size && end_idx < right_size && 
                temp_index[start_idx] != -1 && temp_index[end_idx] != -1 &&
                temp_index[start_idx] < temp_index[end_idx]) {
                prefix_sum[temp_index[start_idx] + 1]++;
                prefix_sum[temp_index[end_idx]]--;
            }
        }
        
        // Aggiungi vincoli per conflitti diretti
        for (int i = 0; i < node_segments[node * 2 + 1].size(); i++) {
            int start_idx = node_segments[node * 2 + 1][i].first - right_start;
            int end_idx = node_segments[node * 2 + 1][i].second - right_start;
            
            if (start_idx < right_size && end_idx < right_size && 
                temp_index[start_idx] != -1 && temp_index[end_idx] != -1 &&
                temp_index[start_idx] < temp_index[end_idx]) {
                add_constraint(node_segments[node * 2 + 1][i].first, 
                             sorted_by_end[temp_index[end_idx]].first, false);
            }
        }
        
        // Calcola prefix sum e aggiungi vincoli tra intervalli consecutivi
        for (int i = 1; i <= sorted_by_end.size(); i++) {
            prefix_sum[i] += prefix_sum[i - 1];
        }
        for (int i = 0; i < (int)sorted_by_end.size() - 1; i++) {
            if (prefix_sum[i] > 0) {
                add_constraint(sorted_by_end[i].first, sorted_by_end[i + 1].first, true);
            }
        }
    }
    
    // Calcola la soluzione con divide and conquer
    void solve() {
        for (int level = LOG - 1; level >= 0; level--) {
            for (int node_idx = 0; node_idx < (1 << level); node_idx++) {
                int node = (1 << level) + node_idx;
                int segment_start = node_idx << (LOG - level);
                int segment_end = ((node_idx + 1) << (LOG - level)) - 1;
                
                if (!is_valid) return;
                
                solve_node_conflicts(node, segment_start, segment_end);
                solve_left_child_conflicts(node, segment_start, segment_end);
                solve_right_child_conflicts(node, segment_start, segment_end);
                
                // Merge degli intervalli dai figli
                for (int i = 0; i < node_segments[node * 2].size(); i++) {
                    node_segments[node].push_back(node_segments[node * 2][i]);
                }
                for (int i = 0; i < node_segments[node * 2 + 1].size(); i++) {
                    node_segments[node].push_back(node_segments[node * 2 + 1][i]);
                }
            }
        }
    }
};

IntervalSolver solver;

int main() {
    int num_intervals;
    scanf("%d", &num_intervals);
    
    solver.init();
    vector<pii> intervals;
    
    // Lettura input
    for (int i = 0; i < num_intervals; i++) {
        int start, end;
        scanf("%d%d", &start, &end);
        start--; end--;
        intervals.push_back(make_pair(start, end));
        solver.add_interval(start, end);
    }
    
    uf.init();
    solver.solve();
    
    // Verifica consistenza
    for (int i = 0; i < num_intervals; i++) {
        if (uf.find(intervals[i].first * 2) == uf.find(intervals[i].first * 2 + 1)) {
            solver.is_valid = false;
            break;
        }
    }
    
    if (!solver.is_valid) {
        printf("0\n");
        return 0;
    }
    
    // Conta componenti connesse
    int component_count = 0;
    for (int i = 0; i < num_intervals; i++) {
        if (uf.find(intervals[i].first * 2) == intervals[i].first * 2) {
            component_count++;
        }
        if (uf.find(intervals[i].first * 2 + 1) == intervals[i].first * 2 + 1) {
            component_count++;
        }
    }
    
    int result = 1;
    int mod = 1000000007;
    for (int i = 0; i < component_count / 2; i++) {
        result = (result * 2) % mod;
    }
    
    printf("%d\n", result);
    return 0;
}

Compilation message (stderr)

port_facility.cpp: In function 'int main()':
port_facility.cpp:302:10: warning: ignoring return value of 'int scanf(const char*, ...)' declared with attribute 'warn_unused_result' [-Wunused-result]
  302 |     scanf("%d", &num_intervals);
      |     ~~~~~^~~~~~~~~~~~~~~~~~~~~~
port_facility.cpp:310:14: warning: ignoring return value of 'int scanf(const char*, ...)' declared with attribute 'warn_unused_result' [-Wunused-result]
  310 |         scanf("%d%d", &start, &end);
      |         ~~~~~^~~~~~~~~~~~~~~~~~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...