1 条题解

  • 0
    @ 2026-6-1 15:17:15

    线段树方法: 首先第一步是破环成链,将圆从 N 到 1 之间剪开,展平成一条 1 到 NN 的一维数轴。

    在数轴上,画一条弦 (A,B)(A, B)(假设 A<BA < B),本质上就是确定了一个区间。并且将点AA的值设为BB,点BB的值设为AA,用来表示弦的存在和对应关系。

    针对区间相交情况,有以下三种可能:

    • 包含: 不相交。
    • 分离: 不相交。
    • 交错(十字交叉): 只有当两根弦的端点呈 A1<A2<B1<B2A_1 < A_2 < B_1 < B_2 排列时,才会在圆内相交。

    转换为线段树: 画弦 (A,B)(A,B),转换为搜索[A,B][A,B] 中所有元素的最大值和最小值,令当前位置为ii,如果ii对应的点仍然在[A,B][A,B] 范围中,显然包含;如果在范围外,必然是交错关系。

    所以只需要维护区间对应的点的最大值和最小值,然后进行判断即可。针对单调修改和区间查询的线段树做出针对性修改即可AC,不需要懒信息。

    时间复杂度: 初始化建树 O(N)O(N);每次询问执行一次查询和两次单点修改,单次 O(logN)O(\log N)。总时间复杂度为 O(N+QlogN)O(N + Q \log N)

    空间复杂度: 线段树采用 4 倍空间数组,空间复杂度为 O(N)O(N)

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    #define endl '\n'
    
    const double EPS = 1e-8;
    const int MAXN = 1e6 + 5;
    
    #define ls (p << 1)
    #define rs (p << 1 | 1)
    int arr[MAXN];
    int mx[MAXN << 2], mn[MAXN << 2];
    
    void push_up(int p) {
        mx[p] = max(mx[ls], mx[rs]);
        mn[p] = min(mn[ls], mn[rs]);
    }
    
    void build() {
        for (int i = 1; i < (MAXN << 2); i++) {
            mx[i] = INT_MIN;
            mn[i] = INT_MAX;
        }
    }
    
    pair<int, int> query(int L, int R, int l, int r, int p) {
        // L、R位置加弦
        if (L <= l && r <= R) {
            return {mn[p], mx[p]};
            // return pair{mn[p], mx[p]}; C++14会报错
            // 要么不写pair 要么make_pair(mn[p], mx[p])
            // 要么pair<int, int>(mn[p], mx[p]);
    
        }
        int mid = (l + r) >> 1;
    
        int min_val = INT_MAX, max_val = INT_MIN;
    
        if (L <= mid) {
            auto temp = query(L, R, l, mid, ls);
            min_val = min(min_val, temp.first);
            max_val = max(max_val, temp.second);
        }
        if (R > mid) {
            auto temp = query(L, R, mid + 1, r, rs);
            min_val = min(min_val, temp.first);
            max_val = max(max_val, temp.second);
        }
    
        return {min_val, max_val};
    }
    
    void update(int idx, int v, int l, int r, int p) {
        // 范围内
        if (l == r) {
            mx[p] = max(mx[p], v);
            mn[p] = min(mn[p], v);
            return;
        }
    
        int mid = (l + r) >> 1;
        if (idx <= mid) {
            update(idx, v, l, mid, ls);
        } else {
            update(idx, v, mid + 1, r, rs);
        }
    
        push_up(p);
    }
    
    signed main() {
        ios::sync_with_stdio(0);
        cin.tie(0), cout.tie(0);
    
        int N, Q;
        cin >> N >> Q;
        build();
        for (int i = 0; i < Q; i++) {
            int A, B;
            cin >> A >> B;
            if (A > B)
                swap(A, B);
            // 连接弦
            auto temp = query(A , B , 1, N, 1);
            // 判断
            if (temp.second > B || temp.first < A) {
                cout << "No" << endl;
            } else {
                cout << "Yes" << endl;
                // 并且加弦 修改
                update(A, B, 1, N, 1);
                update(B, A, 1, N, 1);
            }
        }
    
        return 0;
    }
    
    • 1

    信息

    ID
    686
    时间
    1000ms
    内存
    256MiB
    难度
    提高
    标签
    递交数
    61
    已通过
    13
    上传者