제출 #484242

#제출 시각아이디문제언어결과실행 시간메모리
484242blue조이터에서 친구를 만드는건 재밌어 (JOI20_joitter2)C++17
100 / 100
1077 ms72656 KiB
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
#include <queue>
#include <cassert>
using namespace std;

const int maxN = 100'000;

vector<int> label(1+maxN);
set<int> out_edge[1+maxN]; //label to label
set<int> in_edge[1+maxN];
vector<int> label_list[1+maxN];
set<int> in_count[1+maxN];

// vector<int> in_count(1+maxN, 0);

int sz(int u)
{
    return int(label_list[u].size());
}


long long answer = 0;


long long comp(int u)
{
    u = label[u];
    return (long long)(in_count[u].size()) * (long long)(label_list[u].size());
}

void insert_in(int B, int A)
{
    answer -= comp(label[B]);
    in_count[label[B]].insert(A);
    answer += comp(label[B]);
}

queue< pair<int, int> > join_queue;


void join(int u, int v)
{
    u = label[u];
    v = label[v];

    if(u == v) return;

    assert(u != v);

    answer -= comp(u);
    answer -= comp(v);

    out_edge[u].erase(v);
    out_edge[v].erase(u);
    in_edge[u].erase(v);
    in_edge[v].erase(u);

    if(sz(u) < sz(v)) swap(u, v);

    for(int l: label_list[v])
    {
        label_list[u].push_back(l);
        label[l] = u;
    }

    for(int ic: in_count[v]) in_count[u].insert(ic);

    for(int o: out_edge[v])
    {
        out_edge[u].insert(o);
        in_edge[o].erase(v);
        in_edge[o].insert(u);
        // assert(label[o] == o);

        if(out_edge[o].find(u) != out_edge[o].end())
            join_queue.push(make_pair(o, u));
    }

    for(int i: in_edge[v])
    {
        in_edge[u].insert(i);
        out_edge[i].erase(v);
        out_edge[i].insert(u);
        // assert(label[i] == i);

        if(in_edge[i].find(u) != in_edge[i].end())
            join_queue.push(make_pair(i, u));
    }

    answer += comp(u);

    in_count[v].clear();
    label_list[v].clear();
    out_edge[v].clear();
    in_edge[v].clear();
}


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

    int N, M;
    cin >> N >> M;


    for(int i = 1; i <= N; i++)
    {
        label[i] = i;
        label_list[i].push_back(i);
        in_count[i].insert(i);
    }


    for(int j = 1; j <= M; j++)
    {
        int A, B;
        cin >> A >> B;

        insert_in(B, A);

        A = label[A];
        B = label[B];

        // cerr << "label = " << A << ' ' << B << '\n';

        if(A != B)
        {
            out_edge[A].insert(B);
            in_edge[B].insert(A);



            if(out_edge[B].find(A) != out_edge[B].end())
            {
                join_queue.push(make_pair(A, B));
            }

            while(!join_queue.empty())
            {
                auto g = join_queue.front();
                join_queue.pop();
                join(g.first, g.second);
            }
        }

        cout << answer << '\n';



        // cerr << "\n operation done\n";
        // cerr << "labels: ";
        // for(int i = 1; i <= N; i++) cerr << label[i] << ' ';
        // cerr << '\n';
        //
        // for(int i = 1; i <= N; i++)
        // {
        //     cerr << "out edge " << i << ": ";
        //     for(int o: out_edge[i]) cerr << o << ' ';
        //     cerr << '\n';
        // }
        // cerr << "\n\n";
    }

    // for(int i = 1; i <= N; i++) cerr << label[i] << ' ';
    // cerr << '\n';
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...