Princess principal - 牛客

题意

有一个\(n\)个括号的文档,括号由\(m\)种。我们定义用如下的方式定义一个合法的文档

  • 一个空字符串是一个合法的文档

  • 如果\(A\),\(B\)都是合法的文档,那么\(AB\)也是合法的文档

  • 如果\(S\)是合法的文档,那么\(aSb\)也是合法的文档,其中\(a,b\)是同一种括号

现给出\(q\)个询问,问\([l,r]\)范围内是否是合法文档。

\(1 \le n, m, q \le 10^6\)

方法一

直接差分,orzzzzz。和只有一种括号的差分是一样一样的。遍历到左括号加一,遍历到匹配的右括号减一,用栈来实现保证了这样做的正确性。。。。

代码

const int N = 1000005;

int n, m, q;
int a[N], ans[N];

stack<int> st;

int main()
{
    sc(n), sc(m), sc(q);
    Rep(i, 1, n) sc(a[i]);

    ans[0] = 0;
    Rep(i, 1, n) {
        if (st.empty() || (a[i] & 1) == 0) st.push(i);
        else {
            if (a[st.top()] == a[i] - 1) st.pop();
            else st.push(i);
        }
        if (st.empty()) ans[i] = 0;
        else ans[i] = st.top();
    }

    Rep(i, 1, q) {
        int l, r;
        sc(l), sc(r);
        puts((ans[l - 1] == ans[r] ? "Yes" : "No"));
    }

    return 0;
}

方法二

先找出不能匹配的位置,① \([l,r]\)包含这些位置就直接判断;② \([l,r]\)是合法位置的子串:对于一个括号,它如果能合法匹配,就记录它匹配的括号的位置。然后查询\([l,r]\)范围内括号的匹配位置pos是否存在\(pos < l\)或者\(pos > r\)

代码

const int N = 1000005;

int n, m, q, tot;
int use[N], sum[N], le[N], re[N], Min[4 * N], Max[4 * N];

P p[N];

void Pushup(int root) {
    Min[root] = min(Min[lson], Min[rson]);
    Max[root] = max(Max[lson], Max[rson]);
}

void Build(int l, int r, int root) {
    if (l == r) {
        tot++;
        Min[root] = le[tot];
        Max[root] = re[tot];
        return;
    }
    int mid = (l + r) >> 1;
    Build(l, mid, lson);
    Build(mid + 1, r, rson);
    Pushup(root);
}

int QueryMin(int l, int r, int root, int L, int R) {
    if (l > R || r < L) return INF32;
    if (L <= l && r <= R) return Min[root];
    int mid = (l + r) >> 1;
    int ans = INF32;
    ans = min(ans, QueryMin(l, mid, lson, L, R));
    ans = min(ans, QueryMin(mid + 1, r, rson, L, R));
    return ans;
}

int QueryMax(int l, int r, int root, int L, int R) {
    if (l > R || r < L) return 0;
    if (L <= l && r <= R) return Max[root];
    int mid = (l + r) >> 1;
    int ans = 0;
    ans = max(ans, QueryMax(l, mid, lson, L, R));
    ans = max(ans, QueryMax(mid + 1, r, rson, L, R));
    return ans;
}

int main()
{
    sc(n), sc(m), sc(q);
    Rep(i, 1, n) {
        le[i] = INF32;
        re[i] = 0;

        sc(p[i].first);
        p[i].first = ((p[i].first & 1) ? p[i].first / 2 + m : p[i].first / 2);
        p[i].second = i;
    }
    stack<P> st;
    Rep(i, 1, n) {
        if (st.empty()) st.push(p[i]);
        else {
            if (p[i].first >= m) {
                P tp = st.top();
                st.pop();
                if (tp.first != p[i].first - m) {
                    st.push(p[i]);
                    st.push(tp);
                }
                else {
                    re[tp.second] = p[i].second;
                    le[p[i].second] = tp.second;
                }
            }
            else {
                st.push(p[i]);
            }
        }
    }
    while(!st.empty()) {
        P tp = st.top();
        st.pop();
        use[tp.second] = 1;
    }

    Rep(i, 1, n) sum[i] = sum[i - 1] + use[i];
    
    Build(1, n, 1);

    while(q--) {
        int l, r;
        sc(l), sc(r);

        if (use[l] || (sum[l] != sum[r]) || QueryMax(1, n, 1, l, r) > r || QueryMin(1, n, 1, l, r) < l) puts("No");
        else puts("Yes");
    }

    return 0;
}
posted @ 2018-10-01 20:52  天之道,利而不害  阅读(192)  评论(0编辑  收藏  举报