Submission #1239386

#TimeUsernameProblemLanguageResultExecution timeMemory
1239386orcslopZamjene (COCI16_zamjene)C++20
112 / 140
6096 ms233756 KiB
#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>
#include <map>

using namespace std;

// DSU structure to manage components (clouds)
struct DSU {
    vector<int> parent;
    vector<long long> sz;
    DSU(int n) {
        parent.resize(n + 1);
        iota(parent.begin(), parent.end(), 0);
        sz.assign(n + 1, 1);
    }

    int find(int i) {
        if (parent[i] == i)
            return i;
        return parent[i] = find(parent[i]);
    }
};

// Use two hash functions to minimize collisions
const long long M1 = 1e9 + 7, P1 = 313;
const long long M2 = 1e9 + 9, P2 = 331;
const long long PAIR_P1 = 31;
const long long PAIR_P2 = 37;

// Function to compute a hash for a diff map
pair<long long, long long> get_hash(const map<int, int>& m) {
    if (m.empty()) {
        return {0, 0};
    }
    long long h1 = 0, h2 = 0;
    for (auto const& [val, count] : m) {
        long long pair_hash_1 = (val * PAIR_P1 + count) % M1;
        if (pair_hash_1 < 0) pair_hash_1 += M1;
        long long pair_hash_2 = (val * PAIR_P2 + count) % M2;
        if (pair_hash_2 < 0) pair_hash_2 += M2;
        h1 = (h1 * P1 + pair_hash_1) % M1;
        h2 = (h2 * P2 + pair_hash_2) % M2;
    }
    return {h1, h2};
}

// Function to calculate the hash of the complementary diff map
pair<long long, long long> get_complement_hash(const map<int, int>& m) {
    map<int, int> complement;
    for (auto const& [val, count] : m) {
        complement[val] = -count;
    }
    return get_hash(complement);
}

// Global state variables
DSU dsu(0);
vector<int> p;
vector<map<int, int>> diffs;
vector<pair<long long, long long>> component_hashes;
int bad_components_count = 0;
long long total_q4_pairs = 0;
map<pair<long long, long long>, long long> hash_to_total_size;

// Helper to update total pairs when a group's size changes
void update_pairs(pair<long long, long long> hash, pair<long long, long long> comp_hash, long long old_size, long long new_size){
    if (hash == make_pair(0LL, 0LL)) return;
    
    long long old_size_comp = hash_to_total_size[comp_hash];
    if (hash == comp_hash) {
         old_size_comp = old_size;
    }
    
    // Remove old contribution
    if(hash != comp_hash) {
        total_q4_pairs -= old_size * old_size_comp;
    } else {
        total_q4_pairs -= old_size * (old_size - 1) / 2;
    }

    // Add new contribution
    long long new_size_comp = hash_to_total_size[comp_hash];
     if (hash == comp_hash) {
         new_size_comp = new_size;
    }

    if(hash != comp_hash) {
        total_q4_pairs += new_size * new_size_comp;
    } else {
        total_q4_pairs += new_size * (new_size - 1) / 2;
    }
}


// Modifies a component's diff map and updates all global states
void modify_component_diff(int root, int val, int count_delta) {
    long long size = dsu.sz[root];
    pair<long long, long long> old_hash = component_hashes[root];

    // Remove old state's contribution
    if(!diffs[root].empty()){
        pair<long long, long long> old_comp_hash = get_complement_hash(diffs[root]);
        update_pairs(old_hash, old_comp_hash, hash_to_total_size[old_hash], hash_to_total_size[old_hash] - size);
        if(old_hash != old_comp_hash)
            update_pairs(old_comp_hash, old_hash, hash_to_total_size[old_comp_hash], hash_to_total_size[old_comp_hash]);
        hash_to_total_size[old_hash] -= size;
        bad_components_count--;
    }
    
    diffs[root][val] += count_delta;
    if (diffs[root][val] == 0) {
        diffs[root].erase(val);
    }
    
    pair<long long, long long> new_hash = get_hash(diffs[root]);
    component_hashes[root] = new_hash;
    
    // Add new state's contribution
    if(!diffs[root].empty()){
        pair<long long, long long> new_comp_hash = get_complement_hash(diffs[root]);
        hash_to_total_size[new_hash] += size;
        update_pairs(new_hash, new_comp_hash, hash_to_total_size[new_hash] - size, hash_to_total_size[new_hash]);
        if(new_hash != new_comp_hash)
            update_pairs(new_comp_hash, new_hash, hash_to_total_size[new_comp_hash], hash_to_total_size[new_comp_hash]);
        bad_components_count++;
    }
}


int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    int n, q;
    cin >> n >> q;

    p.resize(n + 1);
    vector<int> q_array(n + 1);
    dsu = DSU(n);
    diffs.resize(n + 1);
    component_hashes.resize(n + 1, {0, 0});

    for (int i = 1; i <= n; ++i) {
        cin >> p[i];
        q_array[i] = p[i];
    }

    sort(q_array.begin() + 1, q_array.end());

    // Initialize components and their hashes
    for (int i = 1; i <= n; ++i) {
        if (p[i] != q_array[i]) {
            diffs[i][p[i]]++;
            diffs[i][q_array[i]]--;
             if (diffs[i][p[i]] == 0) diffs[i].erase(p[i]);
             if (diffs[i].count(q_array[i]) && diffs[i][q_array[i]] == 0) diffs[i].erase(q_array[i]);
        }
        if (!diffs[i].empty()) {
             component_hashes[i] = get_hash(diffs[i]);
             hash_to_total_size[component_hashes[i]]++;
             bad_components_count++;
        }
    }

    // Initialize total_q4_pairs
    for(auto const& [hash, size] : hash_to_total_size) {
        pair<long long, long long> comp_hash = get_complement_hash({ {1,1} }); // Placeholder to call func
        // This is tricky, need to generate comp_hash without a map.
        // Let's compute it from a dummy map for now, though this is inefficient.
        // A better way would be a function that computes complement hash directly from hash.
        // But for simplicity of fix:
        map<int,int> dummy_map; // Create a map that would produce `hash`. Can't do easily.
                                // Instead, we iterate and match.
    }
    // Simple initialization loop
    map<pair<long long, long long>, bool> visited;
    for(auto const& [hash, size] : hash_to_total_size) {
        if (visited[hash]) continue;
        pair<long long, long long> comp_hash = get_complement_hash(diffs[dsu.find(1)]); // Find a component with this hash
        
        int comp_root = -1;
        for(int i=1; i<=n; ++i){ if(component_hashes[i] == hash) {comp_root = i; break;} }
        if(comp_root == -1) continue;
        comp_hash = get_complement_hash(diffs[comp_root]);

        if (hash != comp_hash) {
             total_q4_pairs += size * hash_to_total_size[comp_hash];
        } else {
             total_q4_pairs += size * (size - 1) / 2;
        }
        visited[hash] = true;
        visited[comp_hash] = true;
    }


    for (int k = 0; k < q; ++k) {
        int type;
        cin >> type;
        if (type == 1) {
            int u, v;
            cin >> u >> v;
            int root_u = dsu.find(u);
            int root_v = dsu.find(v);
            
            if (p[u] == p[v]) continue;

            if (root_u != root_v) {
                modify_component_diff(root_u, p[u], -1);
                modify_component_diff(root_u, p[v], 1);
                modify_component_diff(root_v, p[v], -1);
                modify_component_diff(root_v, p[u], 1);
            }
            swap(p[u], p[v]);
        } else if (type == 2) {
            int u, v;
            cin >> u >> v;
            int root_u = dsu.find(u);
            int root_v = dsu.find(v);

            if (root_u != root_v) {
                if (dsu.sz[root_u] < dsu.sz[root_v]) swap(root_u, root_v);

                // --- Remove old components' contributions ---
                long long old_size_u = dsu.sz[root_u];
                pair<long long, long long> old_hash_u = component_hashes[root_u];
                if(!diffs[root_u].empty()) {
                     pair<long long, long long> old_comp_hash_u = get_complement_hash(diffs[root_u]);
                     update_pairs(old_hash_u, old_comp_hash_u, hash_to_total_size[old_hash_u], hash_to_total_size[old_hash_u] - old_size_u);
                     if(old_hash_u != old_comp_hash_u)
                        update_pairs(old_comp_hash_u, old_hash_u, hash_to_total_size[old_comp_hash_u], hash_to_total_size[old_comp_hash_u]);
                     hash_to_total_size[old_hash_u] -= old_size_u;
                     bad_components_count--;
                }

                long long old_size_v = dsu.sz[root_v];
                pair<long long, long long> old_hash_v = component_hashes[root_v];
                 if(!diffs[root_v].empty()) {
                     pair<long long, long long> old_comp_hash_v = get_complement_hash(diffs[root_v]);
                     update_pairs(old_hash_v, old_comp_hash_v, hash_to_total_size[old_hash_v], hash_to_total_size[old_hash_v] - old_size_v);
                     if(old_hash_v != old_comp_hash_v)
                        update_pairs(old_comp_hash_v, old_hash_v, hash_to_total_size[old_comp_hash_v], hash_to_total_size[old_comp_hash_v]);
                     hash_to_total_size[old_hash_v] -= old_size_v;
                     bad_components_count--;
                }
                
                // --- Merge ---
                dsu.parent[root_v] = root_u;
                dsu.sz[root_u] += dsu.sz[root_v];
                
                for (auto const& [val, count] : diffs[root_v]) {
                    diffs[root_u][val] += count;
                    if (diffs[root_u][val] == 0) diffs[root_u].erase(val);
                }
                diffs[root_v].clear();
                
                // --- Add new component's contribution ---
                long long new_size = dsu.sz[root_u];
                pair<long long, long long> new_hash = get_hash(diffs[root_u]);
                component_hashes[root_u] = new_hash;

                if(!diffs[root_u].empty()){
                    pair<long long, long long> new_comp_hash = get_complement_hash(diffs[root_u]);
                    hash_to_total_size[new_hash] += new_size;
                    update_pairs(new_hash, new_comp_hash, hash_to_total_size[new_hash] - new_size, hash_to_total_size[new_hash]);
                     if(new_hash != new_comp_hash)
                        update_pairs(new_comp_hash, new_hash, hash_to_total_size[new_comp_hash], hash_to_total_size[new_comp_hash]);
                    bad_components_count++;
                }

            }
        } else if (type == 3) {
            cout << (bad_components_count == 0 ? "DA\n" : "NE\n");
        } else { // type 4
            cout << total_q4_pairs << "\n";
        }
    }

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