제출 #1343154

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

using ll = long long; using pii = pair<ll,ll>;

const ll Nm = 1e5+5;

ll dsuf[Nm];
set<ll> iedg[Nm]; //edges going into group (ELEMENTS)
set<ll> grp[Nm]; //group members
set<ll> igrp[Nm]; //edges going into group (GROUPS)
set<ll> eloc[Nm]; //what groups does this element have an edge to [inverse of iedg]
set<ll> gloc[Nm]; //what groups does this group have an edge to [inverse of igrp]

ll ans = 0;

ll getf(ll x) {
    if (dsuf[x]==x) {
        return x;
    }
    ll y = getf(dsuf[x]);
    dsuf[x]=y;
    return y;
}

void print(set<ll> s0) {
    for (ll x: s0) {
        cout << x << " ";
    }
    cout << "\n";
}

void mrg(ll a, ll b) { //groups a,b
    a = getf(a); b = getf(b);
    if (a==b) {
        return;
    }
    if ((grp[a].size())>(grp[b].size())) {
        swap(a,b);
    }
    //cout << "running merger on a="<<a<<", b="<<b<<"\n";
    //merge a into b
    ll ga = grp[a].size(); ll gb = grp[b].size();
    ans += (ga+gb)*(ga+gb-1)-ga*(ga-1)-gb*(gb-1);
    for (ll x: grp[a]) { //(x in a) -> b
        if (iedg[b].find(x)!=iedg[b].end()) {
            ans -= gb;
            iedg[b].erase(x);
            eloc[x].erase(b);
        }
    }
    vector<ll> xdel;
    for (ll x: iedg[a]) { //(x in b) -> a
        if (grp[b].find(x)!=grp[b].end()) {
            ans -= ga;
            xdel.push_back(x);
        }
    }
    for (ll x: xdel) {
        iedg[a].erase(x);
        eloc[x].erase(a);
    }
    vector<ll> fmrg;
    for (ll x: gloc[a]) {
        //cout << "gloc[a] term: "<<x<<"\n";
        if (igrp[b].find(x)!=igrp[b].end()) {
            fmrg.push_back(x);
        }
    }
    for (ll x: igrp[a]) {
        if (gloc[b].find(x)!=gloc[b].end()) {
            fmrg.push_back(x);
        }
    }
    for (ll x: grp[a]) { //x in a -> group y
        for (ll y: eloc[x]) {
            igrp[y].erase(a);
            igrp[y].insert(b);
            gloc[a].erase(y);
            gloc[b].insert(y);
        }
    }
    //merge all edges with a/b
    //x -> b: +ga
    ans += ga*iedg[b].size();
    //x -> a: +gb, merge in
    //and x -> a,b: +0 -> correct
    for (ll x: iedg[a]) {
        if (iedg[b].find(x)!=iedg[b].end()) {
            ans -= ga;
        } else {
            iedg[b].insert(x);
            ans += gb;
            eloc[x].erase(a);
            eloc[x].insert(b);
        }
    }
    iedg[a].clear();
    for (ll x: igrp[a]) {
        igrp[b].insert(x);
        gloc[x].erase(a);
        gloc[x].insert(b);
    }
    igrp[a].clear();
    for (ll x: grp[a]) {
        grp[b].insert(x);
    }
    grp[a].clear();
    dsuf[a]=b;
    for (ll x: fmrg) {
        //cout << "execute fmrg: x="<<x<<"\n";
        mrg(x,b);
    }
}

void add(ll a, ll b) {//add a->b
    ll gb = getf(b);
    ll ga = getf(a);
    if (ga==gb) {
        return;
    }
    if (iedg[gb].find(a)!=iedg[gb].end()) {
        return;
    }
    if (igrp[ga].find(gb)!=igrp[ga].end()) {
        //merge groups
        mrg(ga,gb);
    } else {
        //add edge a->gb
        iedg[gb].insert(a);
        igrp[gb].insert(ga);
        eloc[a].insert(gb);
        gloc[ga].insert(gb);
        ans += grp[gb].size();
    }
}

int main() {
	ios_base::sync_with_stdio(false); cin.tie(0);
    ll N,M; cin >> N >> M;
    for (ll i=0;i<N;i++) {
        dsuf[i]=i;
        grp[i].insert(i);
    }
    for (ll m=0;m<M;m++) {
        ll a,b; cin >> a >> b;
        a--; b--;
        add(a,b);
        cout << ans << "\n";
    }
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...