Loading

P6429 [COCI2010-2011#6] STEP 线段树维护最长01

P6429 [COCI2010-2011#6] STEP 线段树维护最长01

题意

给定一个长度为\(n\)的序列\(a\),初始序列中全部都是字符\(L\)

\(q\)次修改,每次修改若\(a_x\)\(L\)则修改为\(R\),否则修改为\(L\)

每次修改后输出最长的连续的不存在连续\(L\)或者\(R\)的子串长度

\[1\leq n ,q\leq 2 \times 10^5 \]

分析

由于要进行修改,考虑用数据结构维护。

经典的线段树套路。

维护结点的\(lv,rv,vv\)分别表示前缀最长的答案,后缀最长的答案和最长的答案。

利用线段树\(push_up\)操作维护\(vv\)

注意一下分类讨论即可。

代码

struct Tree {
    int l, r;
    int lv, rv, vv;
};

Tree node[maxn << 2];
int a[maxn];

void push_up(int i) {
    node[i].lv = node[i << 1].lv;
    node[i].rv = node[i << 1 | 1].rv;
    if (a[node[i << 1].r] != a[node[i << 1|1].l]) {
        if (node[i << 1].lv == node[i << 1].r - node[i << 1].l + 1)
            node[i].lv += node[i << 1 | 1].lv;
        if (node[i << 1 | 1].rv == node[i << 1 | 1].r - node[i << 1 | 1].l + 1)
            node[i].rv += node[i << 1].rv;
    }
    int M = max(node[i << 1].vv, node[i << 1 | 1].vv);
    node[i].vv = max((a[node[i << 1].r] != a[node[i << 1 | 1].l]) ? node[i << 1].rv + node[i << 1|1].lv : 0, M);
}

void update(int i,int x) {
    if (node[i].l == node[i].r) return;
    if (node[i << 1].r >= x)
        update(i << 1, x);
    else
        update(i << 1 | 1, x);
    push_up(i);
}

void build(int i, int l, int r) {
    node[i].l = l;
    node[i].r = r;
    if (l == r) {
        node[i].lv = node[i].rv = node[i].vv = 1;
        return;
    }
    int mid = l + r >> 1;
    build(i << 1, l, mid);
    build(i << 1 | 1, mid + 1, r);
    push_up(i);
}


int main() {
    int n = readint();
    int q = readint();
    build(1, 1, n);
    while (q--) {
        int x = readint();
        a[x] ^= 1;
        update(1, x);
        cout << node[1].vv << '\n';
    }
}
posted @ 2020-10-18 17:03  MQFLLY  阅读(134)  评论(0编辑  收藏  举报