洛谷题单指南-线段树-P6492 [COCI2010-2011#6] STEP

原题链接:https://www.luogu.com.cn/problem/P6492

题意解读:一个序列,初始L,可以指定一个位置修改,L修改成R,R修改成L,可以令L=0,R=1,然后每次修改后输出序列最长不连续0、1(0/1交替出现)的长度。

解题思路:序列支持单点修改(0->1,1->0),区间查询(最长不连续0、1长度),因此可以采用线段树,不需要懒标记。

关键在于找到线段树节点需要维护哪些信息。

比较直观的,节点需要维护区间内不连续0、1的最大长度,设为len

合并逻辑可能有三种情况:

所以,线段树节点需要维护的信息如下:

1、区间内不连续0、1的最大长度len

父节点len = max(左子结点len, 右子节点len, 左子结点sublen + 右子节点prelen)

2、区间内不连续0、1的最大前缀长度prelen

父节点prelen = max(左子结点prelen, 左子结点长度 + 右子节点prelen)

3、区间内不连续0、1的最大后缀长度sublen

父节点sublen = max(右子节点sublen, 右子节点长度 + 左子结点sublen)

4、区间左端点值left

父节点left = 左子结点left

5、区间右端点值right

父节点right = 右子节点right

100分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 200005;

struct Node
{
    int l, r;
    int len, prelen, sublen;
    int left, right;
} tr[N * 4];

int n, m;

void pushup(int u)
{
    Node &root = tr[u];
    Node &lchild = tr[u << 1];
    Node &rchild = tr[u << 1 | 1];

    root.len = max(lchild.len, rchild.len);
    if(lchild.right != rchild.left) 
        root.len = max(root.len, lchild.sublen + rchild.prelen);

    root.prelen = lchild.prelen;
    if(lchild.len == lchild.r - lchild.l + 1 && lchild.right != rchild.left)
        root.prelen = max(root.prelen, lchild.r - lchild.l + 1 + rchild.prelen);
    
    root.sublen = rchild.sublen;
    if(rchild.len == rchild.r - rchild.l + 1 && lchild.right != rchild.left)
        root.sublen = max(root.sublen, rchild.r - rchild.l + 1 + lchild.sublen);
    
    root.left = lchild.left;
    root.right = rchild.right;
}

void build(int u, int l, int r)
{
    tr[u] = {l, r};
    if(l == r) 
    {
        tr[u].len = tr[u].prelen = tr[u].sublen = 1;
        tr[u].left = tr[u].right = 0; //初始都是0
    }
    else
    {
        int mid = l + r >> 1;
        build(u << 1, l, mid);
        build(u << 1 | 1, mid + 1, r);
        pushup(u);
    }
}

void update(int u, int x)
{
    if(tr[u].l == tr[u].r) 
    {
        tr[u].left = tr[u].right = 1 ^ tr[u].left; //0变1,1变0
    }
    else 
    {
        int mid = tr[u].l + tr[u].r >> 1;
        if(x <= mid) update(u << 1, x);
        else update(u << 1 | 1, x);
        pushup(u);
    }
}

int main()
{
    cin >> n >> m;
    build(1, 1, n);
    int x;
    while(m--)
    {
        cin >> x;
        update(1, x);
        cout << tr[1].len << endl;
    }
    return 0;
}

 

posted @ 2024-12-05 17:52  五月江城  阅读(7)  评论(0编辑  收藏  举报