POJ - 3225 - Help with Intervals 【区间的并、交、差、对称差】

http://poj.org/problem?id=3225

两大难点:

1. 区间的集合操作:

2. 区间端点的开、闭的区分方式:

  区间的端点x都要两种状态,要么包含x,要么不含x

  ——可见,每个数其实都要两个值来存储区间的开闭状态,我可以联想到每一个坐标乘以2!

  即,对于区间左端点L,

    L*2代表:[L

    L*2+1代表:(L

  而对于区间右端点R,

    R*2代表:R]

    R*2-1代表:R)

  我们画一下草稿,就可以看出,上述原则实际上是:

  经过计算后的数字k(比如,左闭端点L,计算后为k=L*2; 左开端点L,计算后为k=L*2+1),如果是:

    ① 偶数,代表包含k/2

    ② 奇数,代表一个开区间:( k/2, (k+1)/2 )

#include <cstdio>
#include <iostream>
#define left rt<<1
#define right rt<<1|1
using namespace std;

const int MAXN = (65535 + 5) << 1; // 每一个点都有开、闭两种状态,故乘以2
int XOR[MAXN << 2];
int cover[MAXN << 2];
bool hash[MAXN];

void pushdown(int rt)
{   // cover 优先于 XOR
    if(cover[rt] != -1) {
        cover[left] = cover[right] = cover[rt];
        XOR[left] = XOR[right] = 0;
        cover[rt] = -1;
    }
    if(XOR[rt]) {        // 需判断cover没有被赋值的情况
        if(cover[left] != -1) {
            cover[left] ^= 1;
        } else {
            XOR[left] ^= 1;
        }

        if(cover[right] != -1) {
            cover[right] ^= 1;
        } else {
            XOR[right] ^= 1;
        }
        XOR[rt] = 0;
    }
}

void update(char type, int ql, int qr, int rt, int l, int r)
{
    if(ql <= l && r <= qr) {
        if(type == ‘U‘) {
            cover[rt] = 1;
            XOR[rt] = 0;
        } else if(type == ‘D‘){
            cover[rt] = 0;
            XOR[rt] = 0;
        } else if(type == ‘C‘ || type == ‘S‘) {
            if(cover[rt] != -1)    cover[rt] ^= 1; // 这里要细心,跟上面的pushdown类似
            else    XOR[rt] ^= 1;
        }
        return;
    }    

    pushdown(rt);
    int m = (l + r) >> 1;
    if(ql <= m)    update(type, ql, qr, left, l, m);
    else {
        if(type == ‘I‘ || type == ‘C‘) {
            cover[left] = 0;
            XOR[left] = 0;
        }
    }

    if(qr > m)    update(type, ql, qr, right, m+1, r);
    else {
        if(type == ‘I‘ || type == ‘C‘) {
            cover[right] = 0;
            XOR[right] = 0;
        }
    }
}

void query(int ql, int qr, int rt, int l, int r)
{
    if(cover[rt] != -1) {
        if(cover[rt] == 1) {
            for(int i=l; i<=r; i++) {
                hash[i] = 1;
            }
        }
        return;
    }
    if(l == r)    return;

    pushdown(rt);
    int m = (l + r) >> 1;
    query(ql, qr, left, l, m);
    query(ql, qr, right, m+1, r);
}

int main ()
{
    cover[1] = XOR[1] = 0;
    int a,b;
    char type, l, r;
    while(scanf("%c %c%d,%d%c", &type, &l, &a, &b, &r)!=EOF) {
        a <<= 1;
        b <<= 1;
        if(l == ‘(‘)    a++;
        if(r == ‘)‘)    b--;
        if(a > b) {
            if(type == ‘C‘ || type == ‘I‘) {
                cover[1] = XOR[1] = 0;
            }
        } else {
            update(type, a, b, 1, 0, MAXN); // O(lgn)
        }
        getchar();
    }  

    query(0, MAXN, 1, 0, MAXN); // O(nlgn)
    int s = -1, e, first=1;
    for(int i=0; i<=MAXN; i++) { // O(n)
        if(hash[i] == 1) {
            if(s == -1) {
                s = i;
            }
            e = i;
        } else if(s != -1) {
            if(first)    first = 0;
            else    printf(" ");
            printf("%c%d,%d%c", s&1?‘(‘:‘[‘, s>>1, (e+1)>>1, e&1?‘)‘:‘]‘);
            s = -1;
        }
    }
    if(first)    printf("empty set\n");
    else printf("\n");
    return 0;
} 
时间: 2024-11-05 20:29:12

POJ - 3225 - Help with Intervals 【区间的并、交、差、对称差】的相关文章

poj 3225 Help with Intervals(线段树)

题目链接:poj 3225 Help with Intervals 题目大意:模拟集合操作,输出最终的集合. 解题思路:线段树. U l r:[l,r]区间置为1 I l r:[0,l),(r,maxn]置为0 D l r:[l,r]区间置为0 C l r:[0,l),(r,maxn]置为0,[l,r]区间取逆 S l r:[l,r]区间取逆. 然后基本水水的线段树,注意一下区间开和闭. #include <cstdio> #include <cstring> #include &

poj 3225 Help with Intervals

http://poj.org/problem?id=3225 题意:对集合进行交.并.差.异或四种操作,输出几步操作的之后的集合. U [a,b]  :可以将[a,b]全部置为1:  I [a,b] :可以将[a,b]之外的全部置为0:   S-[a,b] :将[a,b]全部置为0:  [a,b]-s  :将[a,b]之外的全部置为0,[a,b]取反.  I [a,b]  :将[a,b]取反. 然后用线段树维护区间. 1 #include <cstdio> 2 #include <cst

POJ - 3225 Help with Intervals (开闭区间)

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 ti

POJ 3225 Help with Intervals(线段树)

POJ 3225 Help with Intervals 题目链接 集合数字有的为1,没有为0,那么几种操作对应就是置为0或置为1或者翻转,这个随便推推就可以了,然后开闭区间的处理方式就是把区间扩大成两倍,偶数存点,奇数存线段即可 代码: #include <cstdio> #include <cstring> #define lson(x) ((x<<1)+1) #define rson(x) ((x<<1)+2) const int N = 65536

poj 3225 Help with Intervals(线段树,区间更新)

Help with Intervals Time Limit: 6000MS   Memory Limit: 131072K Total Submissions: 12474   Accepted: 3140 Case Time Limit: 2000MS Description LogLoader, Inc. is a company specialized in providing products for analyzing logs. While Ikki is working on g

POJ 3225——Help with Intervals(线段树,成段替换+区间异或+hash)

Help with Intervals Time Limit: 6000MS   Memory Limit: 131072K Total Submissions: 10444   Accepted: 2551 Case Time Limit: 2000MS Description LogLoader, Inc. is a company specialized in providing products for analyzing logs. While Ikki is working on g

(中等) POJ 3225 Help with Intervals , 线段树+集合。

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 ti

POJ 3225(线段树)

POJ 3225 题 意 : 区 间 操 作 , 交 , 并 , 补 等 思 路 : 我 们 一 个 一 个 操 作 来 分 析 :( 用 0 和 1 表 示 是 否 包 含 区 间 , - 1 表 示 该 区 间 内 既 有 包 含 又有 不 包 含 ) U : 把 区 间 [l,r ] 覆 盖 成 1 I: 把 [ - ∞ ,l) ( r, ∞ ] 覆 盖 成 0 D : 把 区 间 [l,r ] 覆 盖 成 0 C : 把 [ - ∞ ,l) ( r, ∞ ] 覆 盖 成 0 , 且 [l

poj 3225 区间(区间的交并补操作)

http://poj.org/problem?id=3225 一道题又做了一天..这道题对我来说起初有N多难点. 1:区间的开闭如何解决.. 2:怎样把区间的交并补.对称差转化为对线段树的操作. 后来与实验室的同学讨论了后解决了前面两个问题. 对于区间的开闭,可以将区间放大一倍,偶数点表示端点,奇数点表示区间内线段,前开的话左端点加1,右开的话右端点减1.例如[1,3]可以表示成[2,6],(1,3)表示成(3,5). 对于区间的交并补问题,可以转化为区间覆盖问题,若T区间为[a,b]. U T