제출 #416567

#제출 시각아이디문제언어결과실행 시간메모리
416567amirmohammad_nezami조이터에서 친구를 만드는건 재밌어 (JOI20_joitter2)C++14
100 / 100
1679 ms88748 KiB
//                                                          In the name of God 
#include <bits/stdc++.h>
using namespace std;
#define F first
#define S second
#define PB push_back
#define MP make_pair
#define lc 2 * v
#define rc 2 * v + 1
#define mid (s + e) / 2
#define _sz(e) (int)e.size()
#define _all(e) e.begin() , e.end()
#define _lcm(a , b) (1ll * a * b) / __gcd(a , b)
#define ll long long
#define int long long
#define ld long double
#define pii pair <int , int>
#define pcc pair <char , char>
#define pll pair <long long , long long>
#define piii pair <int , pair <int , int>>
#define FAST ios::sync_with_stdio(0);cin.tie(0)
#pragma GCC optimize("Ofast")
// #pragma GCC target("sse,sse2,sse3,ssse3,sse4,avmini,avmini2")

const int maxn = 2e5 + 10 , N = 2e6 + 10 , SQ = 320 , base = 800287 , mod = 1e9 + 7 , INF = 1e18 + 10 , lg = 22;
const ld eps = 1e-4;

int n , m , ans , sz[maxn] , par[maxn];
set <int> edges[maxn] , revedges[maxn] , inn[maxn];
queue <pii> q;

int root(int v) {
	return (par[v] == v ? v : par[v] = root(par[v]));
}

inline void add_edge(int v , int u) {
	edges[v].insert(u) , revedges[u].insert(v);
	if(edges[u].find(v) != edges[u].end()) {
		q.push({v , u});
	}
}

void merge(int v , int u) {
	if(v == u) {return ;}
	int sz1 = _sz(edges[v]) + _sz(revedges[v]) + _sz(inn[v]);
	int sz2 = _sz(edges[u]) + _sz(revedges[u]) + _sz(inn[u]);
	if(sz1 < sz2) {swap(v , u);}

	ans += (sz[v] * 1ll * _sz(inn[u])) + (sz[u] * 1ll *  _sz(inn[v]));
	sz[v] += sz[u] , par[u] = v;

	for (auto x : inn[u]) {
		if(inn[v].find(x) != inn[v].end()) {
			ans -= sz[v];
		}
		else {
			inn[v].insert(x);
		}
	}

	edges[v].erase(u) , revedges[v].erase(u);
	edges[u].erase(v) , revedges[u].erase(v);

	for (auto x : edges[u]) {
		revedges[x].erase(u);
		add_edge(v , x);
	}
	for (auto x : revedges[u]) {
		edges[x].erase(u);
		add_edge(x , v);
	}
	edges[u].clear() , revedges[u].clear() , inn[u].clear();
}

int32_t main() {	
	FAST;
	cin >> n >> m;
	iota(par , par + maxn , 0);
	fill(sz , sz + maxn , 1);
	for (int i = 0; i < maxn; ++i) {
		inn[i].insert(i);
	}

	for (int i = 0; i < m; ++i) {
		int x , y; cin >> x >> y;
		x-- , y = root(y - 1);
		if(root(x) == y || inn[y].find(x) != inn[y].end()) {
			cout << ans << '\n';
			continue;
		}

		inn[y].insert(x);
		ans += sz[y];
		add_edge(root(x) , y);

		while(_sz(q)) {
			pii p = q.front();
			merge(root(p.F) , root(p.S));
			q.pop();
		}

		cout << ans << '\n';
	}	
} 

//  Mistakes:
//  * Read the problem carefully.
//  * Check maxn.
//  * Overflows.
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...