Official

E - Chords Editorial by evima


Let’s assume \(A_i < B_i\) without loss of generality.

First, consider cutting open the circular ring between points \(1\) and \(2N\) and straightening it into a line, as shown in the figure below. What were chords on the circular ring are now drawn as curves on the straightened line.

Here, the existence of an intersection between chords on the original circular ring is equivalent to the existence of an intersection between curves in the cut-open state shown on the right side of the figure above (proof omitted). Thus, considering the problem in the cut-open state makes the situation clearer. This idea of cutting open is common when considering the intersection of chords.

Now, let’s consider how to determine the existence of intersections between curves in the cut-open state. The absence of intersections between curves is equivalent to the absence of \(i,j\ (i\neq j)\) such that \(A_i < A_j < B_i < B_j\) (*). This can be determined in \(O(N\log N)\) using a balanced binary tree or a segment tree, but here we introduce an algorithm that uses a stack to determine it in \(O(N)\).

  1. Prepare an empty stack \(S\).
  2. For \(j=1,2,\dots,2N\) in order, do the following:
    • If point \(j\) is the left end of a curve, that is, \(A_i=j\) for some \(i\), then add \(i\) to the end of \(S\).
    • If point \(j\) is the right end of a curve, that is, \(B_i=j\) for some \(i\), then remove one element from the end of \(S\). If the removed element is not \(i\), report the existence of an intersection and terminate the program.
  3. If the program does not terminate by the end, report that there is no intersection.

The proof of the correctness of this algorithm is omitted. If it is difficult to understand intuitively, you might find it more natural to think of the aforementioned condition (*) as follows: When looking from point \(1\) to point \(2N\) from left to right, if the left end of curve \(i\) comes and the left end of another curve \(j\) comes before the right end of curve \(i\) comes, then the right end of curve \(j\) must come before the right end of curve \(i\). Then, it might seem like a somewhat natural idea to manage the curves whose left ends have arrived in a “last in, first out” data structure.

Sample Implementation (C++) :

#include<bits/stdc++.h>

using namespace std;

int main() {
    int n;
    cin >> n;
    vector<pair<int, int>> v(2 * n);
    for (int i = 0; i < n; i++) {
        int a, b;
        cin >> a >> b;
        --a, --b;
        if (a > b) swap(a, b);
        v[a] = {0, i};
        v[b] = {1, i};
    }
    stack<int> st;
    for (int i = 0; i < 2 * n; i++) {
        auto [t, id] = v[i];
        if (!t) {
            st.push(id);
        } else {
            if (st.top() != id) {
                cout << "Yes" << endl;
                return 0;
            }
            st.pop();
        }
    }
    cout << "No" << endl;
}

posted:
last update: