Codeforces
CF Step
Youtube Linkedin Discord Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

Code : Penacony

#include <bits/stdc++.h>
using namespace std;

class LazySegtree {
    int n;
    vector<int> a;

  public:
    LazySegtree(int n) {
        this->n = n;
        a.resize(n);
    }

    void add(int l, int r, int delta) {
        if (l > r) {
            return;
        }
        for (int i = l; i <= r; i++) {
            a[i] += delta;
        }
    }

    int query_freq_of_min(int l, int r) {
        int mn = a[l];
        for (int i = l; i <= r; i++) {
            mn = min(mn, a[i]);
        }
        int freq = 0;
        for (int i = l; i <= r; i++) {
            freq += (a[i] == mn);
        }
        return freq;
    }
};

void solve() {
    int n, m;
    cin >> n >> m;

    LazySegtree st(n);

    vector<vector<int>> adj(n);
    map<pair<int, int>, bool> is_crossover;
    for (int i = 0; i < m; i++) {
        int x, y;
        cin >> x >> y;
        x--, y--;
        st.add(x, y - 1, 1);
        adj[x].push_back(y);
        adj[y].push_back(x);
        is_crossover[{x, y}] = false;
    }

    int ans = n;

    // Before the loop, edge (n - 1, 0) is deleted, that is why there are no
    // crossovers initially.
    //
    // In each iteration, delete edge (x, x + 1)
    for (int x = 0; x < n - 1; x++) {
        // All edges which have one endpoint as x will flip orientation.
        for (auto y : adj[x]) {
            int L = min(x, y), R = max(x, y);
            if (!is_crossover[{L, R}]) {
                // Delete the old contribution.
                st.add(L, R - 1, -1);

                // Add the new contribution.
                st.add(R, n - 1, 1);
                st.add(0, L - 1, 1);
            } else {
                // Delete the old contribution.
                st.add(R, n - 1, -1);
                st.add(0, L - 1, -1);

                // Add the new contribution.
                st.add(L, R - 1, 1);
            }

            is_crossover[{L, R}] = !is_crossover[{L, R}];
        }
        ans = min(ans, n - st.query_freq_of_min(0, n - 1));
    }

    cout << ans << "\n";
}

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

    int t;
    cin >> t;
    for (int i = 0; i < t; i++) {
        solve();
    }
    return 0;
}
#include <atcoder/lazysegtree>
#include <bits/stdc++.h>

using namespace std;
using namespace atcoder;

// S is used for querying minimum element and its frequency.
// (ele, freq)
using S = pair<int, int>;

// op is used for querying.
S op(S a, S b) {
    // If the minimum in both half is equal, frequency will be summed up.
    if (a.first == b.first) {
        return {a.first, a.second + b.second};
    }

    return min(a, b);
}

S e() { return {1e9, 0}; }

// F is used for performing range updates.
using F = int;

F composition(F l, F r) { return l + r; }

F id() { return 0; }

// mapping should return f(x). How does S change when you apply the composition
// on it.
// If you add f to an (ele, freq), it will change to (ele + f, freq)
S mapping(F f, S x) { return {f + x.first, x.second}; }

class LazySegtree {
    int n;
    lazy_segtree<S, op, e, F, mapping, composition, id> *st;

  public:
    LazySegtree(int n) {
        vector<S> initial(n, S{0, 1});
        this->n = n;
        st = new lazy_segtree<S, op, e, F, mapping, composition, id>(initial);
    }

    void add(int l, int r, int delta) {
        if (l > r) {
            return;
        }
        // Atcoder's segtree has [close, open) range.
        st->apply(l, r + 1, delta);
    }

    int query_freq_of_min(int l, int r) { return st->prod(l, r + 1).second; }
};

void solve() {
    int n, m;
    cin >> n >> m;

    LazySegtree st(n);

    vector<vector<int>> adj(n);
    map<pair<int, int>, bool> is_crossover;
    for (int i = 0; i < m; i++) {
        int x, y;
        cin >> x >> y;
        x--, y--;
        st.add(x, y - 1, 1);
        adj[x].push_back(y);
        adj[y].push_back(x);
        is_crossover[{x, y}] = false;
    }

    int ans = n;

    // Before the loop, edge (n - 1, 0) is deleted, that is why there are no
    // crossovers initially.
    //
    // In each iteration, delete edge (x, x + 1)
    for (int x = 0; x < n - 1; x++) {
        // All edges which have one endpoint as x will flip orientation.
        for (auto y : adj[x]) {
            int L = min(x, y), R = max(x, y);
            if (!is_crossover[{L, R}]) {
                // Delete the old contribution.
                st.add(L, R - 1, -1);

                // Add the new contribution.
                st.add(R, n - 1, 1);
                st.add(0, L - 1, 1);
            } else {
                // Delete the old contribution.
                st.add(R, n - 1, -1);
                st.add(0, L - 1, -1);

                // Add the new contribution.
                st.add(L, R - 1, 1);
            }

            is_crossover[{L, R}] = !is_crossover[{L, R}];
        }
        ans = min(ans, n - st.query_freq_of_min(0, n - 1));
    }

    cout << ans << "\n";
}

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

    int t;
    cin >> t;
    for (int i = 0; i < t; i++) {
        solve();
    }
    return 0;
}