PKU 3667

线段树题, 操作有:
    1. 找到线段树中从左数第一段长度大于等于L的连续的0, 返回这段0的左边第一个元素的下标, 如果没有返回0.
    2. 更新一段区间, 使这段区间全为0或者全为1.
从上述操作可以看出, 关键点在于第一个操作.

设置线段树结点结构为:

struct Node {
    int left, right;
    int stat;
    int lmax, rmax, amax;
};

stat = 0 表示区间中的元素全为0, stat = 1 表示区间中的元素全为1, stat = 2 表示区间中既有1也有2.
lmax 表示包括最左边的元素, 最长的连续为0段的长度.
rmax 表示包括最右边的元素, 最长的连续为0段的长度.
amax 表示区间中最长的连续为0段的长度.

#include <iostream>
using namespace std;

const int maxn = 50000 * 3;

struct Node
{
    int left, right;
    int stat;               // 0:区间全为0,1:区间全为1,2:区间有部分为0部分为1
    int lmax, rmax, amax;   // lmax:包含最左边元素最长0的长度,rmax:包含最右边元素最长0的长度
} tree[maxn];               // amax:区间中最长0的长度

void Build(int l, int r, int id)
{
    tree[id].left = l; tree[id].right = r;
    tree[id].stat = 0;
    tree[id].lmax = tree[id].rmax = tree[id].amax = r - l + 1;
    if (l == r) return;

    int m = (l + r) / 2;
    Build(l, m, id * 2);
    Build(m + 1, r, id * 2 + 1);
}

void UpdateStatus(int id)
{
    if (tree[id].stat == 2)
    {
        if (tree[id*2].stat == tree[id*2+1].stat && tree[id*2].stat != 2)
            tree[id].stat = tree[id*2].stat;
    }
}

void UpdateLength(int id)
{
    if (tree[id].stat == 0)
        tree[id].lmax = tree[id].rmax = tree[id].amax =
                    tree[id].right - tree[id].left + 1;
    else if (tree[id].stat == 1)
        tree[id].lmax = tree[id].rmax = tree[id].amax = 0;
    else
    {
        tree[id].amax = max(max(tree[id*2].amax, tree[id*2+1].amax), tree[id*2].rmax + tree[id*2+1].lmax);
        tree[id].lmax = tree[id*2].lmax;
        tree[id].rmax = tree[id*2+1].rmax;
        if (tree[id*2].stat == 0)
            tree[id].lmax += tree[id*2+1].lmax;
        if (tree[id*2+1].stat == 0)
            tree[id].rmax += tree[id*2].rmax;
    }
}

void Update(int l, int r, int v, int id)    // v = 0:更新一段区间为0, v = 1:更新一段区间为1
{
    if (tree[id].stat == v)
        return;

    if (tree[id].left == l && tree[id].right == r)
    {
        tree[id].stat = v;
        UpdateLength(id);
        return;
    }
    if (tree[id].stat != 2)
    {
        tree[id*2].stat = tree[id*2+1].stat = tree[id].stat;
        tree[id].stat = 2;
        UpdateLength(id*2);
        UpdateLength(id*2+1);
    }
    int m = (tree[id].left + tree[id].right) / 2;
    if (r <= m)
        Update(l, r, v, id * 2);
    else if (l > m)
        Update(l , r, v, id * 2 + 1);
    else
        Update(l, m, v, id * 2), Update(m + 1, r, v, id * 2 + 1);
    UpdateStatus(id);
    UpdateLength(id);
}

int  Query(int len, int id)
{
    if (tree[id].stat == 0)
        return tree[id].left;
    if (tree[id*2].amax >= len)
        return Query(len, id * 2);
    else if (tree[id*2].rmax + tree[id*2+1].lmax >= len)
        return tree[id*2].right - tree[id*2].rmax + 1;
    else
        return Query(len, id * 2 + 1);
}

int main()
{
    int N, M;
    int cmd, len, x;

    scanf("%d %d", &N, &M);
    Build(1, N, 1);
    for (int i = 0; i < M; i++)
    {
        scanf("%d", &cmd);
        if (cmd == 1)
        {
            scanf("%d", &len);
            if (tree[1].amax < len)
                printf("0\n");
            else
            {
                x = Query(len, 1);
                Update(x, x + len - 1, 1, 1);
                printf("%d\n", x);
            }
        }
        else
        {
            scanf("%d %d", &x, &len);
            Update(x, x + len - 1, 0, 1);
        }
    }
    return 0;
}


你可能感兴趣的:(struct,tree,cmd,query,Build)