poj2777

题意:有一个长板子,多次操作,有两种操作,第一种是给从a到b那段染一种颜色c,另一种是询问a到b有多少种不同的颜色。

分析:线段树,通过这题才真正理解了线段树的基本思想,无论是更新还是查询都要遵循一个原则,当线段恰好覆盖一个节点的区间时就直接对该节操作而不再向下操作。绝对不能把区间内所有节点全部一代到底,到叶子节点。

对于这种线段树,要在获得整块区间时停止并把该节点的end改为true。以后其他更新或询问需要向下走时再按照该节点的信息进行子节点的信息进行修改,然后向下再进行。

这题还学到一个重要的技巧,当数据范围较小时一定要考虑位操作。颜色最多30种,用位操作,一个整数可以表示一段的颜色状态。

View Code
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;

#define maxn 100004

struct Node
{
    int color;
    int l, r;
    Node *pleft, *pright;
    bool end;
} tree[maxn * 3];

int n, t, o, ncount;

void buildtree(Node *proot, int l, int r)
{
    proot->l = l;
    proot->r = r;
    proot->color = 1;
    proot->end = true;
    if (l == r)
        return;
    int mid = (l + r) / 2;
    ncount++;
    proot->pleft = tree + ncount;
    ncount++;
    proot->pright = tree + ncount;
    buildtree(proot->pleft, l, mid);
    buildtree(proot->pright, mid + 1, r);
}

void paint(Node *proot, int l, int r, int color)
{
    if (proot->l == l && proot->r == r)
    {
        proot->end = true;
        proot->color = color;
        return;
    }
    if (proot->end)
    {
        proot->end = false;
        proot->pleft->color = proot->color;
        proot->pleft->end = true;
        proot->pright->color = proot->color;
        proot->pright->end = true;
    }
    int mid = (proot->l + proot->r) / 2;
    if (r <= mid)
        paint(proot->pleft, l, r, color);
    else if(l > mid)
    paint(proot->pright, l, r, color);
    else
    {
        paint(proot->pleft, l, mid, color);
        paint(proot->pright, mid +1, r, color);
    }
    proot->color = proot->pleft->color | proot->pright->color;
}

int query(Node *proot, int l, int r)
{
    if (proot->end)
        return proot->color;
    if (proot->l == l && proot->r == r)
        return proot->color;
    int mid = (proot->l + proot->r) / 2;
    if (r <= mid)
        return query(proot->pleft, l, r);
    else if(l > mid)
    return query(proot->pright, l, r);
    return query(proot->pleft, l, mid) | query(proot->pright, mid + 1, r);
}

int countbit(int a)
{
    int x = 1;
    int ret = 0;
    for (int i = 0; i < 32; i++, x <<= 1)
        if (x & a)
            ret++;
    return ret;
}

int main()
{
//    freopen("t.txt", "r", stdin);
    ncount = 0;
    scanf("%d%d%d", &n, &t, &o);
    getchar();
    buildtree(tree, 1, n);
    for (int i = 0; i < o; i++)
    {
        char order;
        int l, r, c;
        scanf("%c", &order);
        if (order == 'C')
        {
            scanf("%d%d%d", &l, &r, &c);
            if (l > r)
                swap(l, r);
            paint(tree, l, r, 1 << (c - 1));
        }
        else
        {
            scanf("%d%d", &l, &r);
            if (l > r)
                swap(l, r);
            printf("%d\n", countbit(query(tree, l, r)));
        }
        getchar();
    }
    return 0;
}

 

posted @ 2011-05-14 17:54  金海峰  阅读(2969)  评论(2编辑  收藏  举报