poj 3225 Help with Intervals

题目链接如下:

3225 -- Help with Intervals

感谢大佬:

POJ 3225(线段树) - starry_sky - 博客园

一道线段树的题。

首先看看转化:

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 互 换

定义一个cover数组,用来表示是否覆盖,0表示没有覆盖这个区间,1表示覆盖,-1表示现在没有操作,依旧是lazy标记。

除此之外,还要有一个xor数组,代表这个区间是否是翻转的。

那使用上我们如果要翻转一个区间,先给xor打上标记,0代表不反转,1代表反转,所以很多操作做需要用异或来完成。

那翻转一个区间要做的就是,把xor数组向下push_down,直到遇到了一个cover的lazy tag表示这个区间是否覆盖了。然后可以对cover进行异或就完成了翻转。

对开区间闭区间也做了处理,对所有数字都乘以2,如果是闭区间就把数字放到奇数的位置,这样在处理的时候就巨方便。

代码如下所示:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<vector>
#include<algorithm>
#include<cstring>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<cmath>
#include<climits>

using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int MAXN=65555*2;
bool interval[MAXN];
int cover[MAXN<<2],XOR[MAXN<<2];

void FXOR(int rt){
    if (cover[rt]!=-1) cover[rt]^=1;
    else XOR[rt]^=1;
};

void push_down(int rt){
    if (cover[rt]!=-1){// 说明要覆盖区间 子树的XOR无效 直接赋0
        cover[rt<<1]=cover[rt<<1|1]=cover[rt];
        XOR[rt<<1]=XOR[rt<<1|1]=0;
        cover[rt]=-1;
    }
    if (XOR[rt]){
        FXOR(rt<<1);
        FXOR(rt<<1|1);
        XOR[rt]=0;
    }
}

void update(char op,int a,int b,int l,int r,int rt){
    if (a<=l && r<=b){
        if (op=='U'){
            cover[rt]=1;
            XOR[rt]=0;
        }else if (op=='D'){
            cover[rt]=0;
            XOR[rt]=0;
        }else if (op=='C' || op=='S'){
            FXOR(rt);
        }
        return;
    }
    push_down(rt);
    int mid=(l+r)>>1;
    if (a<=mid){
        update(op,a,b,lson);
    }else if (op=='I' || op=='C'){
        XOR[rt<<1]=cover[rt<<1]=0;
    }
    if (b>mid){
        update(op,a,b,rson);
    }else if (op=='I' || op=='C'){
        XOR[rt<<1|1]=cover[rt<<1|1]=0;
    }
}

void query(int l,int r,int rt){
    if (cover[rt]==1){
        for (int i = l; i <= r; ++i) {
            interval[i]=true;
        }
        return;
    }else if (cover[rt]==0) return;
    if (l==r) return;
    push_down(rt);
    int mid=(l+r)>>1;
    query(lson);
    query(rson);
}

int main(){
    cover[1]=XOR[1]=0;
    char op,l,r;
    int a,b;
//    int count=0;
    while (~scanf("%c %c%d,%d%c\n",&op,&l,&a,&b,&r)){
//        cout<<op<<" "<<l<<a<<","<<b<<r<<endl;
        a<<=1,b<<=1;
        if (l=='(') a++;
        if (r==')') b--;
        if (a>b){
            if (op=='C'||op=='I'){
                cover[1]=XOR[1]=0;
            }
        } else{
            update(op,a,b,0,MAXN,1);
        }
//        if (count++>=5) break;
    }
    query(0,MAXN,1);
    bool flag=false;
    int s=-1,e;
    for (int i = 0; i <= MAXN; ++i) {
        if (interval[i]){
            if (s==-1) s=i;
            e=i;
        } else{
            if (s!=-1){
                if (flag) printf(" ");
                printf("%c%d,%d%c",(s&1 ? '(':'['),s>>1,(e+1)>>1,(e&1 ? ')':']'));
                flag=true;
                s=-1;
            }
        }
    }
    if (!flag) printf("empty set");
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值