[COCI 2010/2011 #6] STEP

GitHub跳转原题关系图返回列表

维护二进制字符序列的最长交替连续子串,支持单点翻转。

OJ: luogu

题目 ID: P6492

难度:普及+/提高

标签:线段树字符串交替序列python

日期: 2026-07-16 23:59

题意

初始全为 L,每次翻转一个位置的 L/R,输出最长相邻字符交替的连续子串长度。

思路

节点保存首字符、尾字符、交替前缀、交替后缀和最大交替段。合并时只有左尾和右首不同,跨越中点的后缀与前缀才能拼接;若整个左(右)段都是交替段,前(后)缀也可以延长。

Python 知识

  • ^= 1 是布尔状态翻转的简洁写法。
  • 初始化全相同序列时不必逐叶建值,只需把每个节点的长度作为交替前后缀。
  • 首尾状态用 bytearray,长度统计用 array("i"),大规模节点也能保持紧凑。

代码

python
import sys
from array import array


sys.setrecursionlimit(1_000_000)
input = sys.stdin.buffer.readline
n, operations = map(int, input().split())
first = bytearray(4 * n)
last = bytearray(4 * n)
prefix = array("i", [0]) * (4 * n)
suffix = array("i", [0]) * (4 * n)
best = array("i", [0]) * (4 * n)


def pull(node, left_length, right_length):
    left, right = node * 2, node * 2 + 1
    different = last[left] != first[right]
    first[node] = first[left]
    last[node] = last[right]
    prefix[node] = prefix[left] + prefix[right] if different and prefix[left] == left_length else prefix[left]
    suffix[node] = suffix[right] + suffix[left] if different and suffix[right] == right_length else suffix[right]
    best[node] = max(best[left], best[right], suffix[left] + prefix[right] if different else 0)


def build(node, left, right):
    prefix[node] = suffix[node] = best[node] = right - left + 1
    if left == right:
        return
    middle = (left + right) // 2
    build(node * 2, left, middle)
    build(node * 2 + 1, middle + 1, right)
    pull(node, middle - left + 1, right - middle)


def update(node, left, right, position):
    if left == right:
        first[node] ^= 1
        last[node] = first[node]
        return
    middle = (left + right) // 2
    if position <= middle:
        update(node * 2, left, middle, position)
    else:
        update(node * 2 + 1, middle + 1, right, position)
    pull(node, middle - left + 1, right - middle)


build(1, 1, n)
answers = []
for _ in range(operations):
    position = int(input())
    update(1, 1, n, position)
    answers.append(str(best[1]))
print("\n".join(answers))

原有 C++ 版本仍保留:

cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-07-16 23:46
 * update_at: 2026-07-16 23:46
 */
#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    return 0;
}

复杂度

每次单点翻转 O(log n),空间 O(n)

总结

“交替”只依赖相邻边界是否不同,因此首尾字符加四个长度统计量就足够合并。