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

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

题意

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

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

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

[1leq n ,qleq 2 imes 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 << '
';
    }
}
原文地址:https://www.cnblogs.com/hznumqf/p/13836043.html