제출 #1134172

#제출 시각아이디문제언어결과실행 시간메모리
1134172Zbyszek99Making Friends on Joitter is Fun (JOI20_joitter2)C++20
0 / 100
6 ms12096 KiB
#include <bits/stdc++.h> #include <ext/pb_ds/assoc_container.hpp> #include <ext/pb_ds/tree_policy.hpp> #define ll long long #define ld long double #define ull unsigned long long #define ff first #define ss second #define pii pair<int,int> #define pll pair<long long, long long> #define vi vector<int> #define vl vector<long long> #define pb push_back #define rep(i, b) for(int i = 0; i < (b); ++i) #define rep2(i,a,b) for(int i = a; i <= (b); ++i) #define rep3(i,a,b,c) for(int i = a; i <= (b); i+=c) #define count_bits(x) __builtin_popcountll((x)) #define all(x) (x).begin(),(x).end() #define siz(x) (int)(x).size() #define forall(it,x) for(auto& it:(x)) using namespace __gnu_pbds; using namespace std; typedef tree<int, null_type, less<int>, rb_tree_tag,tree_order_statistics_node_update> ordered_set; //mt19937 mt;void random_start(){mt.seed(chrono::time_point_cast<chrono::milliseconds>(chrono::high_resolution_clock::now()).time_since_epoch().count());} //ll los(ll a, ll b) {return a + (mt() % (b-a+1));} const int INF = 1e8+50; const ll INF_L = 1e18+40; const ll MOD = 1e9+7; vi comp[100001]; int rep_[100001]; int siz_[100001]; set<pii> in_v[100001]; set<pii> out_v[100001]; set<pii> comp_edges; set<pii> comp_edges_rev; vector<pii> list_to_union; ll cur_ans = 0; int fint(int v) { if(rep_[v] == v) return v; rep_[v] = fint(rep_[v]); return rep_[v]; } set<int> in_del; bool check(int a, int b) { a = fint(a); b = fint(b); return a != b && comp_edges.find({a,b}) != comp_edges.end() && comp_edges.find({b,a}) != comp_edges.end(); } void onion(int a, int b) { if(siz_[a] > siz_[b]) swap(a,b); cur_ans -= (ll)(siz_[a]) * (ll)(siz_[a]-1); cur_ans -= (ll)(siz_[b]) * (ll)(siz_[b]-1); cur_ans -= (ll)siz(in_v[a]) * (ll)siz_[a]; cur_ans -= (ll)siz(in_v[b]) * (ll)siz_[b]; vector<pii> del; //cout << (ll)siz(in_v[a]) << " " << (ll)siz(in_v[b]) << " " << a << " " << b << " ic\n"; forall(it,in_v[a]) { if(fint(it.ff) == b) { out_v[b].erase(out_v[b].find({it.ss,it.ff})); del.pb(it); } } forall(it,del) { in_v[a].erase(in_v[a].find(it)); } del = {}; forall(it,out_v[a]) { if(fint(it.ff) == b) { in_v[b].erase(in_v[b].find({it.ss,it.ff})); del.pb(it); } } forall(it,del) { out_v[a].erase(out_v[a].find(it)); } del = {}; // cout << "xd\n"; auto it = comp_edges.lower_bound({a,-1}); while(it != comp_edges.end() && (*it).ff == a) { int p1 = a; int p2 = (*it).ss; // cout << p1 << " " << p2 << " comp\n"; it++; comp_edges.erase(comp_edges.find({p1,p2})); comp_edges_rev.erase(comp_edges_rev.find({p2,p1})); if(b != p2) { comp_edges.insert({b,p2}); comp_edges_rev.insert({p2,b}); if(check(b,p2)) list_to_union.pb({b,p2}); } } it = comp_edges_rev.lower_bound({a,-1}); while(it != comp_edges_rev.end() && (*it).ff == a) { int p1 = a; int p2 = (*it).ss; // cout << p1 << " " << p2 << " comp2\n"; it++; comp_edges.erase(comp_edges.find({p2,p1})); comp_edges_rev.erase(comp_edges_rev.find({p1,p2})); if(b != p2) { comp_edges.insert({p2,b}); comp_edges_rev.insert({b,p2}); if(check(b,p2)) list_to_union.pb({b,p2}); } } forall(it,in_v[a]) in_v[b].insert(it); forall(it,out_v[a]) out_v[b].insert(it); rep_[a] = b; siz_[b] += siz_[a]; cur_ans += (ll)(siz_[b]) * (ll)(siz_[b]-1); cur_ans += (ll)siz(in_v[b]) * (ll)siz_[b]; //cout << a << " " << b << " " << (ll)siz(in_v[b]) << " " << siz_[b] << " res\n"; } void try_union() { while(!list_to_union.empty()) { pii w = list_to_union.back(); list_to_union.pop_back(); int a = fint(w.ff); int b = fint(w.ss); if(a == b) continue; onion(a,b); } } int main() { ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0); //random_start(); int n,m; cin >> n >> m; rep2(i,1,n) { rep_[i] = i; siz_[i] = 1; comp[i] = {i}; } rep(i,m) { int a,b; cin >> a >> b; int a2 = a; int b2 = b; a = fint(a); b = fint(b); if(a == b) { cout << cur_ans << "\n"; continue; } auto it = in_v[b].lower_bound({a2,-1}); if(it == in_v[b].end() || (*it).ff != a) { in_v[b].insert({a2,b2}); out_v[a].insert({b2,a2}); cur_ans += siz_[b]; comp_edges.insert({a,b}); comp_edges_rev.insert({b,a}); } if(check(a,b)) { list_to_union.pb({a,b}); } try_union(); cout << cur_ans << "\n"; } }
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...