PKU 3225 Help with Intervals

线段树经典入门题目;

这道题有几点不同的地方:

1. 维护的是集合,一个点或者一段区间都是一个集合,(2,3) 是一个集合,不能简单的用线段代替集合;

2. 用离散的 01 值表示集合,对集合的运算需要转化为 01 区间的异或与赋值操作;

3. 01 区间上进行异或和赋值,在 pushdown 的时候只能存在一个信息,一个线段要么被赋值,要么异或,不能既被赋值,同时进行异或(cover[]和xor[]不能同时有效);

4. 结果要求输出运算结果(集合),在查询时,要做的不是查询到左端点、右端点,而是把被赋值的区间全部标记下来(O(n)),然后一次扫描完成输出,这道题卡了很长时间就是这里没想清楚(既然用了线段树,为什么还要O(n)呢?其实是只需要一次O(n),何必用线段树呢?);

# include <stdio.h>
# include <string.h>

# define ls ((r)<<1)
# define rs ((r)<<1 | 1)
# define mid (((x)+(y))>>1)

# define maxn (65535 * 2)

char cc[maxn << 2], xx[maxn << 2],  hh[maxn+1];
/*************************************************************/
void XOR(int r)
{
    if (cc[r] != -1) cc[r] ^= 1;
    else xx[r] ^= 1;
}

void pushdown(int x, int y, int r)
{
    /* after pushdown cc[r]==-1 && xx[r]==0 */
    if (cc[r] != -1)
    {
        cc[ls] = cc[rs] = cc[r];
        xx[ls] = xx[rs] = 0;
        cc[r] = -1;
    }
    if (xx[r])
    {
        XOR(ls);
        XOR(rs);
        xx[r] = 0;
    }
}

void cover(int x, int y, int r, int s, int t, int val)
{
    if (s<=x && y<=t)
    {
        cc[r] = val;
        xx[r] = 0;
        return ;
    }
    pushdown(x, y, r);
    if (s <= mid) cover(x, mid, ls, s, t, val);
    if (mid+1<=t) cover(mid+1, y, rs, s, t, val);
}

void xxor(int x, int y, int r, int s, int t)
{
    if (s<=x && y<=t)
    {
        XOR(r);
        return ;
    }
    pushdown(x, y, r);
    if (s <= mid) xxor(x, mid, ls, s, t);
    if (mid+1<=t) xxor(mid+1, y, rs, s, t);
}

void query(int x, int y, int r)
{
    int i;
    if (cc[r]!= -1)
    {
        if (cc[r] == 1) for (i = x; i <= y; ++i) hh[i] = 1;
        return ;
    }
    // if (x == y) return ;
    pushdown(x, y, r);
    query(x, mid, ls);
    query(mid+1, y, rs);
}

/*************************************************************/
int main()
{
    freopen("data.in", "r", stdin);
    freopen("data.out", "w", stdout);
    
    int s, t, i, first = 1;
    char op, lp, rp;
    
    while (~scanf("%c %c%d,%d%c\n", &op, &lp, &s, &t, &rp))
    {
        s <<= 1, t <<= 1;
        if (lp == '(') ++s;
        if (rp == ')') --t;
        if (s > t || (s==t && (s&0x1)))
        {
            if (op == 'I' || op == 'C') cc[1] = 0, xx[1] = 0;
            continue;
        }
        switch(op)
        {
            case 'U': cover(0, maxn, 1, s, t, 1);break;
            case 'D': cover(0, maxn, 1, s, t, 0);break;
            case 'I': {
                          if (s>0)       cover(0, maxn, 1, 0, s-1, 0);
                          if (t<maxn) cover(0, maxn, 1, t+1, maxn, 0);
                          break;
                      }
             case 'C': {
                          if (s>0)    cover(0, maxn, 1, 0, s-1, 0);
                          if (t<maxn) cover(0, maxn, 1, t+1, maxn, 0);
                          xxor(0, maxn, 1, s, t);
                          break;
                      }          
             case 'S': xxor(0, maxn, 1, s, t);break;
        }
    }
    query(0, maxn, 1);
    for (i = 0; i <= maxn; ++i)
    {
        if (hh[i])
        {
            if (first) first = 0;
            else putchar(' ');
            printf("%c%d,", i&0x1 ? '(':'[', i>>1);
            while (hh[i]) ++i;
            printf("%d%c", i>>1, (i-1)&0x1 ? ')':']');
        }
    }
    if (first) puts("empty set");
    else putchar('\n');
    
    return 0;
} 

代码写的丑,但是刚好跑到了notonlysuccess的前面,谢谢他的线段树专辑

posted on 2012-08-22 21:44  getgoing  阅读(320)  评论(0编辑  收藏  举报

导航