Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <bits/stdc++.h>
- #define all(x) (x).begin(), (x).end()
- #define itn int
- #define make_unique(x) sort((x).begin(), (x).end()); (x).erase(unique((x).begin(), (x).end()), (x).end())
- using namespace std;
- inline int nxt() {
- int x;
- scanf("%d", &x);
- return x;
- }
- struct Edge {
- int from, to;
- int index;
- bool operator <(const Edge& ot) const {
- return index < ot.index;
- }
- };
- struct Vertex {
- int w;
- vector<int> to; // edge indices
- };
- struct Graph {
- vector<Vertex> vertices;
- vector<Edge> edges;
- vector<long long> *answer;
- int low, high;
- vector<int> color;
- vector<char> used;
- vector<int> index;
- vector<int> lowlink;
- vector<int> st;
- int cur_time;
- vector<int> comp_sizes;
- void dfs(int v, int threshold);
- void solve();
- };
- ostream& operator <<(ostream& ostr, const Graph& g) {
- ostr << "G{" << g.vertices.size() << " vertices, " << g.edges.size() << " edges:";
- for (auto e : g.edges) {
- ostr << " (" << e.from + 1 << " -> " << e.to + 1 << " [" << e.index << "])";
- }
- ostr << "}";
- return ostr;
- }
- void Graph::dfs(int v, int threshold) {
- index[v] = lowlink[v] = cur_time++;
- used[v] = 1;
- st.push_back(v);
- for (int e_id : vertices[v].to) {
- if (edges[e_id].index >= threshold) {
- continue;
- }
- int to = edges[e_id].to;
- if (index[to] == -1) {
- dfs(to, threshold);
- lowlink[v] = min(lowlink[v], lowlink[to]);
- } else if (used[to]) {
- lowlink[v] = min(lowlink[v], index[to]);
- }
- }
- if (lowlink[v] == index[v]) {
- int clr = comp_sizes.size();
- comp_sizes.push_back(0);
- while (true) {
- int w = st.back();
- st.pop_back();
- color[w] = clr;
- comp_sizes.back() += vertices[w].w;
- used[w] = 0;
- if (w == v) {
- break;
- }
- }
- }
- }
- #define cerr if (0) cerr
- void Graph::solve() {
- if (low >= high) {
- return;
- }
- if (edges.empty()) {
- return;
- }
- int idx = (low + high + 1) / 2;
- /* if ((*answer)[idx] == 0) {
- (*answer)[idx] = (*answer)[low];
- cerr << "answer[" << idx << "] = answer[" << low << "]\n";
- }
- */
- cerr << "[" << low << ", " << high << "]: " << (*this) << "\n";
- color.assign(vertices.size(), 0);
- used.assign(vertices.size(), 0);
- index.assign(vertices.size(), -1);
- lowlink.assign(vertices.size(), -1);
- st = {};
- cur_time = 0;
- comp_sizes = {};
- for (int v = 0; v < (int)vertices.size(); ++v) {
- if (index[v] == -1) {
- dfs(v, idx);
- }
- }
- cerr << "colors:";
- for (int i = 0; i < (int)vertices.size(); ++i) {
- cerr << " " << color[i];
- }
- cerr << "\n";
- long long tmp = 0;
- for (auto s : comp_sizes) {
- tmp += 1ll * s * (s - 1) / 2;
- }
- for (auto v : vertices) {
- tmp -= 1ll * v.w * (v.w - 1) / 2;
- }
- (*answer)[idx] += tmp;
- (*answer)[high + 1] -= tmp;
- cerr << "answer[" << idx << "] += " << tmp << "\n\n";
- vector<Graph> left(comp_sizes.size());
- Graph right;
- vector<int> in_graph_index(vertices.size());
- vector<int> total_w(vertices.size());
- for (int i = 0; i < (int)vertices.size(); ++i) {
- in_graph_index[i] = left[color[i]].vertices.size();
- left[color[i]].vertices.push_back({vertices[i].w, {}});
- }
- for (int i = 0; i < (int)comp_sizes.size(); ++i) {
- right.vertices.push_back({comp_sizes[i], {}});
- }
- for (auto e : edges) {
- if (color[e.from] == color[e.to]) {
- if (e.index < idx) {
- left[color[e.from]].vertices[in_graph_index[e.from]].to.push_back(left[color[e.from]].edges.size());
- left[color[e.from]].edges.push_back({in_graph_index[e.from], in_graph_index[e.to], e.index});
- }
- } else {
- right.vertices[color[e.from]].to.push_back(right.edges.size());
- right.edges.push_back({color[e.from], color[e.to], e.index});
- }
- }
- for (auto& g : left) {
- g.low = low;
- g.high = idx - 1;
- g.answer = answer;
- }
- right.low = idx;
- right.high = high;
- right.answer = answer;
- for (auto g : left) {
- g.solve();
- }
- right.solve();
- }
- int main() {
- int n = nxt(), m = nxt();
- vector<long long> answer(m + 2);
- Graph g;
- for (int i = 0; i < n; ++i) {
- g.vertices.push_back({1, {}});
- }
- for (int i = 0; i < m; ++i) {
- int u = nxt() - 1, v = nxt() - 1;
- g.vertices[u].to.push_back(i);
- g.edges.push_back({u, v, i});
- }
- g.answer = &answer;
- g.low = 0;
- g.high = m;
- g.solve();
- answer.pop_back();
- answer.erase(answer.begin());
- for (int i = 1; i < (int)answer.size(); ++i) {
- // answer[i] = max(answer[i], answer[i - 1]);
- answer[i] = (answer[i] + answer[i - 1]);
- }
- for (auto x : answer) {
- printf("%lld\n", x);
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement