POJ 3225 Help with Intervals 线段树

做了好多线段树,顿时感觉线段树博大精深,虽然最基本的只是递归的更新,但是在写线段树的时候需要注意的地方真是太多太多,每个题都有自己要注意的地方,每个题都有自己的解决问题的小技巧,因而做线段树的时候需要自己对于线段树有特定的分析和不同的做法,好了感慨完了开始说题。

本题说的是对一排数进行操作,主要有四个

OperationNotation

Definition

UnionA ∪ B{x : x ∈ A or x ∈ B}
IntersectionA ∩ B{x : x ∈ A and x ∈ B}
Relative complementationA − B{x : x ∈ A but x ∉ B}
Symmetric differenceA ⊕ B(A − B) ∪ (B − A)
CommandSemantics
U TS ← S ∪ T
I TS ← S ∩ T
D TS ← S − T
C TS ← T − S
S TS ← S ⊕ T
问进行完若干个操作之后这一列数还剩多少。一开始为空集;

以输入为例:

U [1,5]
D [3,3]
S [2,4]
C (1,5)
I (2,3]
一开始对空集区并得到[1,5];然后集合与[3,3]做差得到[1,3)和(3,5],以此类推直到得到最终结果
(2,3)
这道题要注意的地方其实还是不少的首先是对于开括号和闭括号的操作,如何分别开括号和闭括号,解决方法是对每个数乘以二,这样整点数字用他的两倍来表示,两个数倍增之后中间的奇数则表示两个数之间的小数,比如2,3分别用电4,6来表示,而5则会表示(2,3)表示的数字。
另一个需要注意的地方也就是线段树的更新,这个如果做的线段树比较多的话也不算是新知识,就是如何使用pushdown();
在使用pushdown()的时候需要把父节点的cover设置为-1而不是0或者1;

void pushdown(int o)
{
    if(cover[o] != -1)
    {
        cover[o << 1] = cover[o << 1 | 1] = cover[o];
        XO[o << 1] = XO[o << 1 | 1] = 0;
        cover[o] = -1;
    }
    if(XO[o])
    {
        FOX(o << 1);
        FOX(o << 1 | 1);
        XO[o] = 0;
    }
}
这个还要靠以后多做题,培养意识。
<pre name="code" class="cpp">#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <functional>
#include <cstdio>
#include <queue>
#include <map>
#include <algorithm>
#include <stack>
#include <utility>
typedef long long ll;
using namespace std;
const int mx = 131072;
int cover[mx << 2],XO[mx << 2];
int numl[mx],numr[mx];
int qr,ql,cnt;
char a;
bool has[mx];
void FOX (int o)
{
    if(cover[o] != -1)cover[o] ^= 1;
    else XO[o] ^= 1;
}
void pushdown(int o)
{
    if(cover[o] != -1)
    {
        cover[o << 1] = cover[o << 1 | 1] = cover[o];
        XO[o << 1] = XO[o << 1 | 1] = 0;
        cover[o] = -1;
    }
    if(XO[o])
    {
        FOX(o << 1);
        FOX(o << 1 | 1);
        XO[o] = 0;
    }
}
//void pushup(int o)
//{
//    if(cover[o << 1] == 1&& cover[o << 1|1] == 1)
//        cover[o] = 1;
//    if(cover[o << 1] == 0&& cover[o << 1|1] == 0)
//        cover[o] = 0;
//}
void update(int o = 1,int L = 0,int R = mx - 1)
{
    if(ql <= L&&qr >= R)
    {
        if(a == 'U')
        {
            cover[o] = 1;
            XO[o] = 0;
        }
        if(a == 'D')
        {
            cover[o] = 0;
            XO[o] = 0;
        }
        if(a == 'C'|| a == 'S') FOX(o);
//        printf("o = %d L = %d R = %d cover = %d XO = %d\n",o,L,R,cover[o],XO[o]);
        return;
    }
    pushdown(o);
    int mid = (R + L) >> 1;
    if(ql <= mid) update (o << 1,L,mid);
    else
    {
        if(a == 'I' || a == 'C')
        {
            cover[o << 1] = 0;
            XO [o << 1] = 0;
        }
    }
    if(qr > mid) update(o << 1 | 1,mid + 1,R);
    else
    {
        if(a == 'I' ||a == 'C')
        {
            cover[o << 1 | 1] = 0;
            XO [o << 1 | 1] = 0;
        }
    }
//    printf("o = %d L = %d R = %d cover = %d XO = %d\n",o,L,R,cover[o],XO[o]);
}
void qu(int o = 1,int L = 0,int R = mx - 1)
{

    if(cover[o] == 1)
    {
        for(int i = L; i <= R; i++)
            has[i] = true;
        return;
    }
    if(cover[o] == 0)
        return;
    if(R == L)
        return;
    pushdown(o);
    int mid = (R + L) >> 1;
    qu(o << 1,L,mid);
    qu(o << 1| 1,mid + 1,R);
}
int main ()
{
    char b,c,d;
    cover[1] = XO[1] = 0;
    while (~scanf("%c %c%d,%d%c",&a,&b,&ql,&qr,&c))
    {
        getchar();
        ql <<= 1;
        qr <<= 1;
        if(b == '(') ql++;
        if(c == ')') qr--;
        if(ql > qr)
        {
            if(a == 'C' || a == 'I')
                cover[1] = XO[1] = 0;
            continue;
        }
        update();
    }
    int l,r,i,k,j;
    cnt = 0;
    qu();
    bool flag = false;
    int s = -1 , e;
    for (int i = 0 ; i <= mx ; i ++)
    {
        if (has[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");
    puts("");
    return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值