POJ 3225 Help with Intervals (线段树)

Help with Intervals
Time Limit: 6000MSMemory Limit: 131072K
Total Submissions: 7937Accepted: 1842
Case Time Limit: 2000MS

Description

LogLoader, Inc. is a company specialized in providing products for analyzing logs. While Ikki is working on graduation design, he is also engaged in an internship at LogLoader. Among his tasks, one is to write a module for manipulating time intervals, which have confused him a lot. Now he badly needs your help.

In discrete mathematics, you have studied several basic set operations, namely union, intersection, relative complementation and symmetric difference, which naturally apply to the specialization of sets as intervals.. For your quick reference they are summarized in the table below:

OperationNotation

Definition

UnionAB{x : xA or xB}
IntersectionAB{x : xA and xB}
Relative complementationAB{x : xA but x B}
Symmetric differenceAB(AB) ∪ (BA)

Ikki has abstracted the interval operations emerging from his job as a tiny programming language. He wants you to implement an interpreter for him. The language maintains a set S, which starts out empty and is modified as specified by the following commands:

CommandSemantics
U TSST
I TSST
D TSST
C TSTS
S TSST

Input

The input contains exactly one test case, which consists of between 0 and 65,535 (inclusive) commands of the language. Each command occupies a single line and appears like

X T

where X is one of ‘U’, ‘I’, ‘D’, ‘C’ and ‘S’ and T is an interval in one of the forms (a,b), (a,b], [a,b) and [a,b] (a, bZ, 0 ≤ ab ≤ 65,535), which take their usual meanings. The commands are executed in the order they appear in the input.

End of file (EOF) indicates the end of input.

Output

Output the set S as it is after the last command is executed as the union of a minimal collection of disjoint intervals. The intervals should be printed on one line separated by single spaces and appear in increasing order of their endpoints. If S is empty, just print “empty set” and nothing else.

Sample Input

U [1,5]
D [3,3]
S [2,4]
C (1,5)
I (2,3]

Sample Output

(2,3)
 
线段树成端更新,此题比较难处理的地方:答案的区间开闭判断,以及分析五种操作的不同之处和实现方法。
首先要明白操作的含义(在草稿本上画几种情况就好理解了):假设T=[l,r]
U  把[l,r]区间更新为1
I  把[0,l-1],[r+1,MAX]更新为0
D  把[l,r]区间更新为0
C 把[0,l-1,[r+1,MAX]更新为0,再把[l,r]进行异或操作,既0变成1,1变成0
S  把[l,r]进行异或操作
对于答案判断区间开闭,可以借鉴POJ1436的做法,既把输入的区间左右端点都乘上2,这样的话(2,4)就可以表示为[5,7].因为(2,4)乘上2得到(4,6),通过乘以2,所有区间端点都是偶数,如果是左端是‘(’,就将左端点++得到奇数,右端是‘)’,则将右端点--。这样就可以实现如果是偶数,说明是闭的,奇数则说明是开的。当然,左右端点的开闭输出时要注意把右端点+1再除以2,因为之前进行了--操作,会使结果变小(向下取整的问题)。
还有值得注意的是,全部更新为0或1的操作是优先于异或操作的,因为如果该需要更新的区间已经全部为0,那么异或其实就相当于把它全部改成1.同时,统计答案的时候也是通过查询区间的,异或只是一个标记。统计时只需对整个区间往下查找,如果遇到整个区间都是1的时候,用bool数组通过循环从左到右标记一下该区间。
 
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define SIZE 66666*2
#define ls l,mid,rt<<1
#define rs mid+1,r,rt<<1|1

using namespace std;

int change[SIZE<<2],XOR[SIZE<<2];
bool vis[SIZE];

void pushDown(int rt)
{
    if(change[rt] != -1)
    {
        change[rt<<1] = change[rt<<1|1] = change[rt];
        XOR[rt<<1] = XOR[rt<<1|1] = 0;
        change[rt] = -1;
    }
    if(XOR[rt] != 0)
    {
        if(change[rt<<1] != -1)
            change[rt<<1] ^= 1;
        else
            XOR[rt<<1] ^= 1;
        if(change[rt<<1|1] != -1)
            change[rt<<1|1] ^= 1;
        else
            XOR[rt<<1|1] ^= 1;
        XOR[rt] = 0;
    }
}

void update(int l,int r,int rt,int L,int R,int w)
{
    if(L <= l && r <= R)
    {
        change[rt] = w;
        XOR[rt] = 0;
        return;
    }
    pushDown(rt);
    int mid = (l + r) >> 1;
    if(L <= mid) update(ls,L,R,w);
    if(R > mid) update(rs,L,R,w);
}

void do_XOR(int l,int r,int rt,int L,int R)
{
    if(L <= l && r <= R)
    {
        if(change[rt] != -1)
            change[rt] ^= 1;
        else
            XOR[rt] ^= 1;
        return;
    }
    pushDown(rt);
    int mid = (l + r) >> 1;
    if(L <= mid) do_XOR(ls,L,R);
    if(R > mid) do_XOR(rs,L,R);
}

void query(int l,int r,int rt)
{
    if(change[rt] == 1)
    {
        for(int i=l; i<=r; i++)
            vis[i] = true;
        return;
    }
    else if(change[rt] == 0)
        return;
    if(l == r) return;
    pushDown(rt);
    int mid = (l + r) >> 1;
    query(ls);
    query(rs);
}

char op,ll,rr;
int s,e;

int main()
{
    change[1] = XOR[1] = 0;
    while(~scanf("%c ",&op))
    {
        scanf("%c%d,%d%c",&ll,&s,&e,&rr);
        getchar();
        s <<= 1; e <<= 1;
        if(ll == '(') s ++;
        if(rr == ')') e --;
        if(s > e)
        {
            if(op == 'C' || op == 'I')
                change[1] = XOR[1] = 0;
            continue;
        }
        if(op == 'U')
            update(0,SIZE,1,s,e,1);
        if(op == 'I')
        {
            if(s > 0)
                update(0,SIZE,1,0,s-1,0);
            update(0,SIZE,1,e+1,SIZE,0);
        }
        if(op == 'D')
            update(0,SIZE,1,s,e,0);
        if(op == 'C')
        {
            if(s > 0)
                update(0,SIZE,1,0,s-1,0);
            update(0,SIZE,1,e+1,SIZE,0);
            do_XOR(0,SIZE,1,s,e);
        }
        if(op == 'S')
            do_XOR(0,SIZE,1,s,e);
    }
    memset(vis,0,sizeof(vis));
    query(0,SIZE,1);
    bool flag = false;
    int st = -1,ed = -1;
    for(int i=0; i<=SIZE; i++)
    {
        if(vis[i])
        {
            if(st == -1)
                st = i;
            ed = i;
        }
        else
        {
            if(st != -1)
            {
                if(flag)
                    printf(" ");
                flag = true;
                if(st & 1)
                    printf("(");
                else
                    printf("[");
                printf("%d,%d",st>>1,(ed+1)>>1);
                if(ed & 1)
                    printf(")");
                else printf("]");
                st = -1;
            }
        }
    }
    if(!flag) printf("empty set");
    printf("\n");
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值