[COCI2010-2011#6] STEP
sol:
这道题类似区间最大子段和。我们维护 lm, rm, ms,分别表示左右最长子串,全局最长子串。pushup的时候,计算ms时,应该为左右儿子内部的ms与跨越左右区间的ms的最大值。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 2e5 + 100;
struct Node {
int l, r;
int lm, rm, ms;
} tr[N << 2];
int n, q;
bool a[N];
void pushup(int u) {
Node & ls = tr[u << 1], rs = tr[u << 1 | 1];
tr[u].lm = ls.lm;
if( ls.lm == ls.r - ls.l + 1 && a[ls.r] ^ a[rs.l])
tr[u].lm = max(tr[u].lm, ls.lm + rs.lm);
tr[u].rm = rs.rm;
if( rs.rm == rs.r - rs.l + 1 && a[rs.l] ^ a[ls.r])
tr[u].rm = max(tr[u].rm, rs.rm + ls.rm);
tr[u].ms = max(ls.ms, rs.ms);
if( a[ls.r] ^ a[rs.l]) {
tr[u].ms = max(tr[u].ms, ls.rm + rs.lm);
}
}
void change(int u, int k) {
if( tr[u].l == tr[u].r) {
a[tr[u].l] ^= 1;
return;
}
int mid = tr[u].l + tr[u].r >> 1;
if(k <= mid) change(u << 1, k);
else change(u << 1 | 1, k);
pushup(u);
}
void build(int u, int l, int r) {
tr[u].l = l, tr[u].r = r;
tr[u].ms = tr[u].lm = tr[u].rm = 1;
if(l == r) return;
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
}
int main()
{
scanf("%d%d", &n, &q);
build(1, 1, n);
while(q --) {
int k;
scanf("%d", &k);
change(1, k);
printf("%d\n", tr[1].ms);
}
return 0;
}
/*
3 1
2
*/