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';
}
}