poj 3225(线段树)

题目链接:http://poj.org/problem?id=3225


题意描述:给你一个集合初始化为空集,然后让它和其他集合进行一系列操作,最后输出操作之后的集合,集合操作有U表示求并集,I表示求交集,D表示S与给出集合求差集,C表示给出集合与S的集合求差集,这里的区间有开有并


分析:假设不考虑区间的开与闭,用线段树来维护所有区间初始化为0

如果是U的话则将(l,r)的值赋值为1

如果是I的话则将(0,l-1)和(r+1,max)的值赋值为1

如果是D的话则将(l,r)赋值为0

如果是C的话则将(0,l-1)(r+1,max)的值赋值为0,将区间(l,r)的区间取反

如果是S的话则将(l,r)区间取反


但是这样都是建立在点树的基础上的,但这里单位区间和点都应该看成点,这里就需要一个转换左闭区间转换为点2*l,将左开区间转换为2*r+1,将右闭区间转换为2*r,将右开区间转换为2*r-1,那么这样之后所有的单位区间为一个点,点也是一个点,这样就可以用线段树来维护啦,具体见代码:


#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=65535*2;
struct node
{
    int l,r;
    int tag;
    int num;
}tree[N*4];

bool vis[N];
void bulid (int rt, int l , int r)
{
    tree[rt].l=l;
    tree[rt].r=r;
    tree[rt].tag=0;
    tree[rt].num=0;
    if(l==r)return;
    int mid=(l+r)>>1;
    bulid(2*rt,l,mid);
    bulid(2*rt+1,mid+1,r);
}

void pushdown(int rt)
{
    if(tree[rt].tag!=-1)
    {
        tree[2*rt].tag=tree[rt].tag;
        tree[2*rt+1].tag=tree[rt].tag;
        tree[rt].tag=-1;
        tree[2*rt].num=tree[2*rt+1].num=tree[rt].num=0;
    }

    if(tree[rt].num)
    {
        if(tree[2*rt].num)
        tree[2*rt].num=0;
        else if(tree[2*rt].tag!=-1) tree[2*rt].tag^=1;
        else tree[2*rt].num=1;

        if(tree[2*rt+1].num)tree[2*rt+1].num=0;
        else if(tree[2*rt+1].tag!=-1) tree[2*rt+1].tag^=1;
        else tree[2*rt+1].num=1;
        tree[rt].num=0;
    }
}
void insert(int rt, int l , int r, int op)
{
     //if(tree[rt].l>l||tree[rt].r<r)return;
    if(op<2)
    {
        if(tree[rt].l==l&&tree[rt].r==r)
        {
            tree[rt].tag=op;
            tree[rt].num=0;
            return;
        }
    }
    else if(op==2)
    {
        if(l==tree[rt].l && r==tree[rt].r)
        {
            if(tree[rt].tag!=-1)
            tree[rt].tag^=1;
            else tree[rt].num^=1;
            return;
        }
    }
    int mid=(tree[rt].l+tree[rt].r)>>1;
    pushdown(rt);
    if(r<=mid)insert(2*rt,l,r,op);
    else if(l>mid)insert(2*rt+1,l,r,op);
    else {insert(2*rt,l,mid,op); insert(2*rt+1,mid+1,r,op);}

    if(tree[2*rt].tag==tree[2*rt+1].tag)
    tree[rt].tag=tree[2*rt].tag;
}

void quary(int rt)
{
    if(tree[rt].l==tree[rt].r)
    {
        vis[tree[rt].l]=tree[rt].tag;
        return;
    }
    pushdown(rt);
    quary(2*rt);
    quary(2*rt+1);
}
int main ()
{
    char op, ch1, ch2;
    int l,r,i,s;
    bulid(1,0,N);
    while(scanf("%c %c%d,%d%c",&op,&ch1,&l,&r,&ch2)!=EOF)
    {
        getchar();
        l=l+l;
        r=r+r;
        if(ch1=='(')
           l++;
        if(ch2==')')
        r--;
        if(l>r)continue;
        switch(op)
        {
            case 'U':
            insert(1,l,r,1);break;
            case 'I':
            if(l>0)
            insert(1,0,l-1,0);
            if(r<N)
            insert(1,r+1,N,0);break;
            case 'D':
            insert(1,l,r,0);break;
            case 'C':
            if(l>0)
            insert(1,0,l-1,0);
            if(r<N)
            insert(1,r+1,N,0);
            insert(1,l,r,2);break;
            case 'S':
            insert(1,l,r,2);break;
        }
    }
    quary(1);
     int begin, end, tmp = 1;
    for(i = 0; i <= N; i++)
    {
        while(i <= N && !vis[i])   i++;
        begin = i;
        if(i > N)    break;

        while(i <= N && vis[i])    i++;
        end = i - 1;

        tmp = 0;
        if(begin&1)
            printf("(%d,", begin/2);
         else
            printf("[%d,", begin/2);


        if(end&1)
            printf("%d) ", (end+1)/2);

        else
            printf("%d] ", end/2);

    }
    if(tmp)
        printf("empty set");
    printf("\n");
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值