이 제출은 이전 버전의 oj.uz에서 채점하였습니다. 현재는 제출 당시와는 다른 서버에서 채점을 하기 때문에, 다시 제출하면 결과가 달라질 수도 있습니다.
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <vector>
#include <algorithm>
#include <fstream>
#include <queue>
#include <deque>
#include <iomanip>
#include <cmath>
#include <set>
#include <stack>
#include <map>
#include <unordered_map>
#define FOR(i,n) for(int i=0;i<n;i++)
#define FORE(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
#define ld long double
//#define int short
#define vi vector<int>
#define pb push_back
#define ff first
#define ss second
#define ii pair<int,int>
#define iii pair<int,ii>
#define pll pair<ll,ll>
#define plll pair<ll,pll>
#define mp make_pair
#define vv vector
#define endl '\n'
using namespace std;
const int MAXN = 1e5+5;
int D = 0;
int E = 0;
int F = 0;
int G = 0;
struct DSU{
ll tot = 0;
int parent[MAXN];
set<int> incoming[MAXN];// individual nodes
set<int> incomingCliques[MAXN];
set<ii> outgoing[MAXN];//
set<int> sentTo[MAXN];
set<int> allNodes[MAXN];
ll sz[MAXN];
DSU(){
FOR(i,MAXN)parent[i] = i;
FOR(i,MAXN)sz[i] = 1;
FOR(i,MAXN)allNodes[i].insert(i);
}
int find(int a){
if(a != parent[a])parent[a] = find(parent[a]);
return parent[a];
}
bool isSame(int a,int b){
return find(a) == find(b);
}
// outgoing[e] = {a,i} means there are i edges going from Supernodes e to a
// we only keep track of outgoing edges + internal clique edges;
inline void addEdge(int a,int b){
b = find(b);
incomingCliques[b].insert(find(a));
incoming[b].insert(a);
sentTo[a].insert(b);
tot += sz[b];
}
void makeParent(int pa,int pb,set<int>& allIncomers){
// make pa parent
for(auto e : incoming[pa]){
if(find(e) != pb)
allIncomers.insert(e);
tot -= sz[pa];
}
for(auto e : incoming[pb]){
if(find(e) != pa)
allIncomers.insert(e);
tot -=sz[pb];
}
for(auto x: allNodes[pb])
for(auto e : sentTo[x]){
incomingCliques[e].erase(pb);
incomingCliques[e].insert(pa);
}
incoming[pa].clear();
incoming[pb].clear();
incomingCliques[pa].clear();
incomingCliques[pb].clear();
//sentTo[pa].clear();
//sentTo[pb].clear();
}
void merge(int a,int b){
int pa = find(a);
int pb = find(b);
tot += 2*sz[pa]*sz[pb]; // new internal edges of the clique.
//allIncomers.clear();
//cout << "COMBINING: " << pa << " " << pb << endl;
if(sz[pa] < sz[pb])swap(pa,pb);
for(auto x : allNodes[pb])allNodes[pa].insert(x);
set<int> allIncomers;
makeParent(pa,pb,allIncomers);
parent[pb] = pa;
sz[pa] += sz[pb];
for(auto e : allIncomers){
handleEdge(e,pa);
}
}
void handleEdge(int a,int b){
//cout <<a << " " << b << endl;
int pa = find(a);
int pb = find(b);
//cout << "We have to handle " << a+1 << " : " << b+1 << endl;
if(pa == pb)return;
// edge is a-> b
if(incoming[pb].find(a) != incoming[pb].end())return;
//cout << "We do have to solve it" << a+1 << " : " << b+1 << endl;
if(incomingCliques[pa].find(pb) != incomingCliques[pa].end()){
merge(a,b);
}else{
addEdge(a,b);
}
}
};
int main(){
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n,m;
cin >> n >> m;
DSU dsu;
FOR(i,m){
int a,b;
cin >> a >> b;
a--;b--;
dsu.handleEdge(a,b);
cout << dsu.tot << endl;
}
return 0;
}
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |