제출 #1249775

#제출 시각아이디문제언어결과실행 시간메모리
1249775mr_finCurtains (NOI23_curtains)C++20
0 / 100
0 ms324 KiB
#include <bits/stdc++.h>
using namespace std;
using vi = vector<int>;

int lg2(int n){
    return 31 - __builtin_clz(n);
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, m, q;
    cin >> n >> m >> q;

    // --- 1) Tính farL và farR ---
    // farL[i] = max r của curtain bắt đầu tại i
    // farR[i] = min l của curtain kết thúc tại i
    vi farL(n+2, 0), farR(n+2, n+1);
    for(int i = 0; i < m; i++){
        int l, r;
        cin >> l >> r;
        farL[l] = max(farL[l], r);
        farR[r] = min(farR[r], l);
    }

    // --- 2) Tính mxS và sufE ---
    // mxS[i] = max_{j <= i} farL[j]
    // sufE[i] = min_{j >= i} farR[j]
    vi mxS(n+2, 0), sufE(n+2, n+1);
    for(int i = 1; i <= n; i++){
        mxS[i] = max(mxS[i-1], farL[i]);
    }
    for(int i = n; i >= 1; i--){
        sufE[i] = min(sufE[i+1], farR[i]);
    }

    // --- 3) Xây nextS và nextE ---
    // nextS[i] = first-uncovered = mxS[i] + 1
    // nextE[i] = first-uncovered từ phải = sufE[i] - 1
    vi nextS(n+2), nextE(n+2);
    for(int i = 1; i <= n; i++){
        nextS[i] = min(n+1, mxS[i] + 1);
        nextE[i] = max(0,    sufE[i] - 1);
    }
    nextS[n+1] = n+1;
    nextE[0]   = 0;

    // --- 4) Build sparse-table (doubling) ---
    int LOG = lg2(n+1) + 1;
    vector<vi> jumpS(LOG, vi(n+2)), jumpE(LOG, vi(n+2));

    // cấp 0
    for(int i = 0; i <= n+1; i++){
        jumpS[0][i] = nextS[i];
        jumpE[0][i] = nextE[i];
    }
    // cấp k>0
    for(int k = 1; k < LOG; k++){
        for(int i = 0; i <= n+1; i++){
            jumpS[k][i] = jumpS[k-1][ jumpS[k-1][i] ];
            jumpE[k][i] = jumpE[k-1][ jumpE[k-1][i] ];
        }
    }

    // --- 5) Xử lý mỗi query ---
    while(q--){
        int S, E;
        cin >> S >> E;

        // Điều kiện căn bản: có curtain bắt đầu che S? có curtain kết thúc che E?
        if(mxS[S] < S || sufE[E] > E){
            cout << "NO\n";
            continue;
        }

        // --- Con trỏ từ trái (S) ---
        int curS = S;
        // nhảy các 2^k bước sao cho vẫn chưa vượt E
        for(int k = LOG-1; k >= 0; k--){
            int nxt = jumpS[k][curS];
            if(nxt <= E){
                curS = nxt;
            }
        }
        // sau cùng, vị trí được phủ tận cùng từ bên S:
        int X = mxS[curS];

        // --- Con trỏ từ phải (E) ---
        int curE = E;
        // nhảy các 2^k bước sao cho vẫn chưa trước S
        for(int k = LOG-1; k >= 0; k--){
            int nxt = jumpE[k][curE];
            if(nxt >= S){
                curE = nxt;
            }
        }
        // sau cùng, vị trí được phủ tận cùng từ bên E:
        int Y = sufE[curE];

        // Nếu hai “giao nhau” hoặc trùng nhau, tức Y <= X, thì có cách ghép kín [S..E]
        cout << (Y <= X ? "YES\n" : "NO\n");
    }

    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...