Submission #1235645

#TimeUsernameProblemLanguageResultExecution timeMemory
1235645notbrainingMaking Friends on Joitter is Fun (JOI20_joitter2)C++20
100 / 100
499 ms65384 KiB
#pragma GCC optimize ("O3")
#include<iostream>
#include<vector>
#include<set>
#include<map>
#include<iomanip>
#include <cassert>
#include<algorithm>
#include <cstring>
#include<unordered_set>
#include<queue>
#include<unordered_map>
#include<numeric>
#include <list>
#include <bitset>
using namespace std;
#define int long long
#define pii pair<int,int>
#define LL long long
int n, m;
int ans = 0;
vector<int>par;
vector<set<int>>groups_followers;
//this group's inividual followers
vector<set<int>>to_big;
vector<set<int>>from_big;
//between groups
queue<pii>q;
int get(int x) { return (par[x] < 0 ? x : (par[x] = get(par[x]))); }
void add_edge(int a, int b){
    a = get(a);
    b = get(b);
    //groups 
    to_big[a].insert(b);
    from_big[b].insert(a);
    if(to_big[b].count(a))
        q.push({a, b});
}

void merge(int a, int b) {
    a = get(a);
    b = get(b);
    if(a == b) return;
    if(groups_followers[a].size() + to_big[a].size() + from_big[a].size() > groups_followers[b].size() + to_big[b].size() + from_big[b].size()) {
        //you'll need to change group's individual followers, group followers, following groups
        swap(a, b);
    }
    //cout << a << " " << b << endl;
    //merge a INTO b

    //add answer
    //All of a's followers follow b, 
    //followers inside group count as well
   // cout << ans << endl;
   /*
       for(int i : groups_followers[b]){
        cout << i << endl;
    }
   */

   // cout << -par[a] << " " << groups_followers[b].size() << " " << (-par[b]) << " " << groups_followers[a].size() << endl;
    ans += (groups_followers[a].size() * (-par[b]) + groups_followers[b].size() * (-par[a]));
    //cout << ans << endl;
    par[b] += par[a];
    par[a] = b;
    for(int i : groups_followers[a]){
        if(groups_followers[b].count(i)){
            //this was already following everyone in group b, subtract it out
            ans -= (-par[b]);
        }
        groups_followers[b].insert(i);
    }
    //do we need this?
    to_big[a].erase(b);
    to_big[b].erase(a);
    from_big[a].erase(b);
    from_big[b].erase(a);
    for(int i : to_big[a]){
        from_big[i].erase(a);
        add_edge(b, i);
    }
    for(int i : from_big[a]){
        to_big[i].erase(a);
        add_edge(i, b);
    }
}
int32_t main(){
    ios_base::sync_with_stdio(0);
    cin.tie(NULL);
    cin >> n >> m;
    par = vector<int>(n + 1, -1);
    groups_followers = vector<set<int>>(n + 1);
    to_big = vector<set<int>>(n + 1);
    from_big = vector<set<int>>(n + 1);
    for(int i = 1; i <= n; ++i)
        groups_followers[i].insert(i);
    while(m--){
        int a, b;
        cin >> a >> b;

        if(m == 0){
            // cout << "m=0:\n";
             /*
                    for(int i = 1;i <= 3; ++i){
                 cout << par[i] << " ";
             }
                             for(int i : groups_followers[4]){
                 cout << i << " ";
             }
             */


             //cout << endl;
        }


        //you need both, a cannot be in b and a cannot follow anyone in b's group
        if(groups_followers[get(b)].count(a) || get(a) == get(b)){
            cout << ans << "\n";
            continue;
        }
        groups_followers[get(b)].insert(a);
        ans += (-par[get(b)]);
        add_edge(get(a), get(b));
        while(!q.empty()){
            a = q.front().first;
            b = q.front().second;
            q.pop();
            //cout << a << " " << b << endl;
            merge(a, b);
        }
        cout << ans << "\n";

    }
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...