POJ 3225 Help with Intervals

题目链接:http://poj.org/problem?id=3225&lang=zh-CN&change=true


题意:对一个区间进行5种操作,问最后覆盖区间

1.U T       当前区间并上区间T

2. I T       当前区间交上区间T

3.D T      将当前区间和区间T的交去掉

4.C T     将T区间中与当前区间的交去掉

5.S T     DT并上CT


思路:可以想到每种操作就是对区间更新,和之前的题目一样使用lazy标记就可以做到,lazy标志不会一直重叠,区间就只有3种情况:被覆盖(lazy==1).没有被覆盖(lazy==0),以及部分覆盖(lazy==-1),不一样的地方某些操作会将区间覆盖翻转(覆盖变成未覆盖,未覆盖变成覆盖),需要用到翻转标记,当lazy标记下传的时候根据翻转标记的奇偶性进行改变;还有注意的是D(3,4)一类的普通的线段树进行更新查询出现[l,2]和[5,r]的情况,和答案[l,3)和(4,r]不一样,也就是说我们没有办法判断开闭区间,这个时候我们要把l和r乘2,如果是(l,r)的话,l++以及r--,最后在判断奇偶性就可以知道是开闭区间了……


将5种操作翻译一下:

1. 将T区间覆盖

2. 将T以外的地方清空

3. 将T区间清空

4.将T区间以外的地方清空,T区间内原来覆盖的地方覆盖,覆盖的地方清空

5.操作3与操作4的并,也就是T区间进行翻转


#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define maxn 65835*2
using namespace std;

struct Tree
{
    int l,r;
}tree[maxn*4];

int lazy[maxn*4],turn[maxn*4],res_l[maxn],res_r[maxn];
int cnt=0;


void build(int root,int l,int r)
{
    tree[root].l=l;
    tree[root].r=r;
    if (l==r) return;

    int mid=(l+r)>>1;
    build(root<<1,l,mid);
    build(root<<1|1,mid+1,r);
}

void pushdown(int root)
{
    if (lazy[root]!=-1)
    {
        if (turn[root]%2==1) lazy[root]=!lazy[root];
        lazy[root<<1]=lazy[root<<1|1]=lazy[root];
        turn[root<<1]=turn[root<<1|1]=turn[root]=0;
        lazy[root]=-1;
    }

    if (turn[root]%2==1)
    {
        turn[root<<1]++;
        turn[root<<1|1]++;
        turn[root]=0;
    }
}



void update(int root,int l,int r,int val,int k)
{
    if (tree[root].l>=l && tree[root].r<=r)
    {
        if (k==1)
        {
            lazy[root]=val;
            turn[root]=0;
        }
        else turn[root]++;
        return;
    }
    pushdown(root);
    int mid=(tree[root].l+tree[root].r)>>1;
    if (l<=mid) update(root<<1,l,r,val,k);
    if (r>mid) update(root<<1|1,l,r,val,k);
}

void que(int root,int l,int r)
{
    if (lazy[root]!=-1)
    {
        if (turn[root]%2==1)
        {//cout<<":"<<lazy[root]<<endl;
            lazy[root]=!lazy[root];
            turn[root]=0;
        }

        if (lazy[root]==1)
        {//cout<<tree[root].l<<":"<<":"<<tree[root].r<<endl;
            res_l[cnt]=tree[root].l;
            res_r[cnt]=tree[root].r;
            cnt++;
        }
        return;
    }

    if (tree[root].l==tree[root].r) return;
    pushdown(root);
    int mid=(tree[root].l+tree[root].r)>>1;

    if (l<=mid) que(root<<1,l,r);
    if (r>mid) que(root<<1|1,l,r);
}


int main()
{
    char op,ll,rr;
    int l,r;
    build(1,0,maxn-1);
    memset(lazy,0,sizeof(lazy));
    memset(turn,0,sizeof(turn));
    cnt=0;
    while (scanf("%c %c%d,%d%c",&op,&ll,&l,&r,&rr)!=EOF)
    {
        l*=2;
        r*=2;
        if (ll=='(') l++;
        if (rr==')') r--;
        if (op=='U')
        {//cout<<l<<":"<<r<<endl;
            if (l<=r)
             update(1,l,r,1,1);
        }
        else if (op=='I')
        {
            if (l>0)
             update(1,0,l-1,0,1);
            update(1,r+1,maxn-1,0,1);
        }
        else if (op=='D')
        {
            if (l<=r)
             update(1,l,r,0,1);
        }
        else if (op=='C')
        {
            if (l>0)
             update(1,0,l-1,0,1);
            update(1,r+1,maxn-1,0,1);
            if (l<=r)
             update(1,l,r,0,0);
        }
        else if (op=='S')
        {
            if (l<=r)
             update(1,l,r,0,0);
        }
        getchar();

    }
    que(1,0,maxn-1);
    if (cnt!=0)
    {
        for (int i=0;i<cnt;i++)
        {
            int tem=i;
            while (i<cnt-1 && res_r[i]==res_l[i+1]-1)
              i++;

            int st=res_l[tem],ed=res_r[i];

            if (st%2==0) printf("[%d,",st/2);
            else printf("(%d,",st/2);

            if (ed%2==0) printf("%d] ",ed/2);
            else printf("%d) ",(ed+1)/2);
        }
    }
    else printf("empty set");
    printf("\n");
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值