POJ 3225 区间(带标记的线段树区间操作)

思路:

1. 因为要对一个区间进行多种操作,特别是相补差和对称差的情况下,要对一个区间操作怎么办?

2. 区间的seg[] = 0, 1, -1,分别表示区间为空,有数据,两者兼有。lab[] = 0, 1 表示区间是否被标记,当seg[] = -1时才会有效(即不确定时)

3. 对区间的5中操作,其实标记主要是为了应对于取反的操作。也算是延迟的一种方式吧,大区间取反,虽然其中可能有0,1,-1,但是最终只是针对0,1取反的。

U:把区间[l,r]覆盖成1
I:把[-∞,l)(r,∞]覆盖成0
D:把区间[l,r]覆盖成0
C:把[-∞,l)(r,∞]覆盖成0 , 且[l,r]区间0/1互换
S:[l,r]区间0/1互换

#include <cstdio>
#include <cstdlib>
#include <cstring>

#define lhs l, m, rt << 1
#define rhs m + 1, r, rt << 1 | 1

const int maxn = 131100;
bool hash[maxn];
int seg[maxn << 2];
int lab[maxn << 2];

void DoXor(int rt)
{
    if (seg[rt] != -1)
        seg[rt] = seg[rt] ^ 1;
    else
        lab[rt] = lab[rt] ^ 1;
}

void PushDown(int rt)
{
    if (seg[rt] != -1)
    {
        seg[rt << 1] = seg[rt << 1 | 1] = seg[rt];
        lab[rt << 1] = lab[rt << 1 | 1] = 0;
        seg[rt] = -1;
    }
    if (lab[rt])
    {
        DoXor(rt << 1);
        DoXor(rt << 1 | 1);
        lab[rt] = 0;
    }
}

void Update(char op, int beg, int end, int l, int r, int rt)
{
    if (beg <= l && r <= end)
    {
        if (op == 'U')
            seg[rt] = 1, lab[rt] = 0;
        else if (op == 'D')
            seg[rt] = 0, lab[rt] = 0;
        else if (op == 'C' || op == 'S')
            DoXor(rt);
    } 
    else
    {
        PushDown(rt);
        int m = (l + r) >> 1;

        if (beg <= m)
            Update(op, beg, end, lhs);
        else if (op == 'I' || op == 'C')
            seg[rt << 1] = lab[rt << 1] = 0;

        if (end > m)
            Update(op, beg, end, rhs);
        else if (op == 'I' || op == 'C')
            seg[rt << 1 | 1] = lab[rt << 1 | 1] = 0;
    }
}

void Query(int l, int r, int rt)
{
    if (seg[rt] == 1)
    {
        for (int i = l; i <= r; ++i)
            hash[i] = true;
        return ;
    }
    else if (seg[rt] == 0 || l == r)
        return ;

    PushDown(rt);

    int m = (l + r) >> 1;
    Query(lhs); Query(rhs);
}

int main()
{
    seg[1] = lab[1] = 0;

    char op, l, r;
    int a, b;
    while (scanf("%c %c%d,%d%c\n", &op, &l, &a, &b, &r) != EOF)
    {
        a <<= 1, b <<= 1;
        if (l == '(')
            ++a;
        if (r == ')')
            --b;

        if (a > b)
        {
            if (op == 'C' || op == 'I')
                seg[1] = lab[1] = 0;
        }
        else
            Update(op, a, b, 0, maxn, 1);
    }

    Query(0, maxn, 1);

    bool flag = false;
    int s = -1, e;

    for (int i = 0; i < maxn; ++i) 
    {
        if (hash[i])
        {
            if (s == -1) s = i;
            e = i;
        } 
        else 
        {
            if (s != -1) 
            {
                if (flag) printf(" ");
                flag = true;
                printf("%c%d,%d%c",s&1?'(':'[' , s>>1 , (e+1)>>1 , e&1?')':']');
                s = -1;
            }
        }
    }
    if (!flag) printf("empty set");
    printf("\n");
    return 0;
}
原文地址:https://www.cnblogs.com/kedebug/p/2867110.html