제출 #1338477

#제출 시각아이디문제언어결과실행 시간메모리
1338477ykilra조이터에서 친구를 만드는건 재밌어 (JOI20_joitter2)C++20
100 / 100
550 ms92400 KiB
#include <bits/stdc++.h>
using namespace std;
#define int long long

const int N = 2e5 + 50;
struct DSU{
    int par[N];
    void init(int n) {
        for (int i = 1; i <= n; i++) par[i] = i;
    }
    int find(int a) {
        return par[a] == a ? a : par[a] = find(par[a]);
    }
}dsu_set;

set<int> in_set[N], in_point[N], out_set[N], ss[N];
// in_set is the set point in, point similar, out similar
// ss is the element in this set
queue<pair<int,int>> q; // For Heruistic Merging

long long calc(int u) {
    return (long long)ss[u].size()*(ss[u].size()-1) + (long long)in_point[u].size()*ss[u].size();
}
long long ans = 0;

typedef std::set<int>::iterator set_it;

void merge(int x, int u) { // Heruistic Merging of two maximum clique
    x = dsu_set.find(x), u = dsu_set.find(u);
    if (x == u) return; // belong to same clique

    if (ss[x].size() < ss[u].size()) swap(x,u); // Heruistic
    dsu_set.par[u] = x;
    ans -= calc(x); ans -= calc(u); // Minus two set
    if (in_set[x].count(u)) in_set[x].erase(u);
    if (out_set[x].count(u)) out_set[x].erase(u);
    for (set_it iter = ss[u].begin(); iter != ss[u].end(); iter++) {
        int a = *iter;
        ss[x].insert(a);
        if (in_point[x].count(a)) in_point[x].erase(a);
    }
    for (set_it iter = in_point[u].begin(); iter != in_point[u].end(); iter++) {
        int a = *iter; 
        if (!in_point[x].count(a) && !ss[x].count(a)) {
            in_point[x].insert(a);
        }
    }
    for (set_it iter = in_set[u].begin(); iter != in_set[u].end(); iter++) {
        int a = *iter; if (a == x) continue;
        out_set[a].erase(u);
        out_set[a].insert(x);
        in_set[x].insert(a);
        if (out_set[x].count(a)) q.push({x,a});
    }
    for (set_it iter = out_set[u].begin(); iter != out_set[u].end(); iter++) {
        int a = *iter; if (a == x) continue;
        in_set[a].erase(u);
        in_set[a].insert(x);
        out_set[x].insert(a);
        if (in_set[x].count(a)) q.push({x,a});
    }
    ans += calc(x);
}

void pop_q() {
    while (!q.empty()) {
        int x = q.front().first,y = q.front().second; q.pop();
        merge(x,y);
    }
}

int32_t main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, m; cin >> n >> m;
    dsu_set.init(n);
    for (int i = 1; i <= n; i++) ss[i].insert(i);
    for (int i = 1; i <= m; i++) {
        int x, y; cin >> x >> y;
        int fx = dsu_set.find(x), fy = dsu_set.find(y);
        if (fx == fy) {
            cout << ans << '\n';
            continue;
        }
        if (in_set[fx].count(fy)) {
            q.push({fx,fy});
            pop_q();
        }
        else {
            ans -= calc(fx); ans -= calc(fy);
            in_set[fy].insert(fx), in_point[fy].insert(x), out_set[fx].insert(fy);
            ans += calc(fx); ans += calc(fy);
        }
        cout << ans << '\n';
    }
    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...