#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>
#include <map>
#include <random>
#include <chrono>
// Use fast I/O
void fast_io() {
std::ios_base::sync_with_stdio(false);
std::cin.tie(NULL);
}
// DSU parent array
std::vector<int> parent;
// Initial array p and sorted array q
std::vector<int> p, q;
// For each component root: map of values it has, map of values it needs, and its size
std::vector<std::map<int, int>> has, needs;
std::vector<int> sz;
// Hashing parameters
long long B1, B2, M;
std::vector<long long> p1, p2;
// Global state variables for O(1) queries
long long good_components;
long long total_components;
long long type4_pairs;
// Map to store sum of component sizes for each hash pair
std::map<std::pair<long long, long long>, long long> hash_to_size_sum;
// --- Hashing Functions ---
// Function to precompute powers for hashing
void precompute_powers(int n) {
p1.resize(n + 1);
p2.resize(n + 1);
p1[0] = p2[0] = 1;
for (int i = 1; i <= n; ++i) {
p1[i] = (p1[i - 1] * B1) % M;
p2[i] = (p2[i - 1] * B2) % M;
}
}
// Function to calculate the hash of a diff map
std::pair<long long, long long> get_hash(const std::map<int, int>& diff) {
long long h1 = 0, h2 = 0;
for (auto const& [val, count] : diff) {
if (count == 0) continue;
long long term1 = (p1[val] * std::abs(count)) % M;
long long term2 = (p2[val] * std::abs(count)) % M;
if (count > 0) {
h1 = (h1 + term1) % M;
h2 = (h2 + term2) % M;
} else {
h1 = (h1 - term1 + M) % M;
h2 = (h2 - term2 + M) % M;
}
}
return {h1, h2};
}
// --- DSU and State Management ---
// DSU find operation with path compression
int find_set(int v) {
if (v == parent[v])
return v;
return parent[v] = find_set(parent[v]);
}
// Helper to calculate the difference map for a component
std::map<int, int> get_diff_map(int root) {
std::map<int, int> diff;
for (auto const& [val, count] : has[root]) {
diff[val] += count;
}
for (auto const& [val, count] : needs[root]) {
diff[val] -= count;
}
return diff;
}
// Function to update global statistics when a component's state changes
void update_stats(int root, int add) {
auto diff = get_diff_map(root);
bool is_good = true;
for (auto const& [val, count] : diff) {
if (count != 0) {
is_good = false;
break;
}
}
if (is_good) {
good_components += add;
} else {
auto h = get_hash(diff);
auto complement_h = std::make_pair((M - h.first) % M, (M - h.second) % M);
long long component_size = sz[root];
if (add == -1) { // Remove contribution
// First, remove this component's effect on the total pairs
if (hash_to_size_sum.count(complement_h)) {
type4_pairs -= component_size * hash_to_size_sum[complement_h];
}
// Then, update the map of hash -> size sums
hash_to_size_sum[h] -= component_size;
} else { // Add contribution
// First, update the map of hash -> size sums
hash_to_size_sum[h] += component_size;
// Then, add this component's new contribution to total pairs
if (hash_to_size_sum.count(complement_h)) {
type4_pairs += component_size * hash_to_size_sum[complement_h];
}
}
}
}
// DSU unite operation
void unite_sets(int a, int b) {
a = find_set(a);
b = find_set(b);
if (a != b) {
// Remove old components from global stats
update_stats(a, -1);
update_stats(b, -1);
// Standard DSU merge by size
if (sz[a] < sz[b]) std::swap(a, b);
// Merge maps
for (auto const& [val, count] : has[b]) {
has[a][val] += count;
}
for (auto const& [val, count] : needs[b]) {
needs[a][val] += count;
}
has[b].clear();
needs[b].clear();
parent[b] = a;
sz[a] += sz[b];
total_components--;
// Add new merged component to global stats
update_stats(a, 1);
}
}
int main() {
fast_io();
int n, q_count;
std::cin >> n >> q_count;
p.resize(n + 1);
q.resize(n + 1);
for (int i = 1; i <= n; ++i) {
std::cin >> p[i];
q[i] = p[i];
}
std::sort(q.begin() + 1, q.end());
// Initialize hashing parameters with random bases
std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());
B1 = std::uniform_int_distribution<long long>(1000001, 1000000006)(rng);
B2 = std::uniform_int_distribution<long long>(1000001, 1000000006)(rng);
M = 1000000007;
precompute_powers(1000000);
// Initialize DSU and component data
parent.resize(n + 1);
std::iota(parent.begin(), parent.end(), 0);
has.resize(n + 1);
needs.resize(n + 1);
sz.assign(n + 1, 1);
total_components = n;
good_components = 0;
type4_pairs = 0;
for (int i = 1; i <= n; ++i) {
has[i][p[i]]++;
needs[i][q[i]]++;
update_stats(i, 1);
}
// Process queries
for (int k = 0; k < q_count; ++k) {
int type;
std::cin >> type;
if (type == 1) {
int u, v;
std::cin >> u >> v;
int root_u = find_set(u);
int root_v = find_set(v);
// Update stats before the swap
update_stats(root_u, -1);
if (root_u != root_v) {
update_stats(root_v, -1);
}
// Update has maps
has[root_u][p[u]]--;
has[root_u][p[v]]++;
if (root_u != root_v) {
has[root_v][p[v]]--;
has[root_v][p[u]]++;
}
// Perform swap
std::swap(p[u], p[v]);
// Update stats after the swap
update_stats(root_u, 1);
if (root_u != root_v) {
update_stats(root_v, 1);
}
} else if (type == 2) {
int u, v;
std::cin >> u >> v;
unite_sets(u, v);
} else if (type == 3) {
if (good_components == total_components) {
std::cout << "DA\n";
} else {
std::cout << "NE\n";
}
} else if (type == 4) {
std::cout << type4_pairs << "\n";
}
}
return 0;
}
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |