zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    asp.net 中theme一个意外问题
    常用的APT命令参数
    使用分布式编译incredbuild错误error C2858: commandline option 'program database name 解决方法
    使用分布式编译incredbuild错误error C2858: commandline option 'program database name 解决方法
    闻名遐迩的MySQL乱码问题(转)
    让你在职场上不可替代的12信条 30句职场箴言
    让你在职场上不可替代的12信条 30句职场箴言
    常用的APT命令参数
    [转]深入理解SET NAMES和mysql(i)_set_charset的区别
    [转]深入理解SET NAMES和mysql(i)_set_charset的区别
  • 原文地址:https://www.cnblogs.com/rainydays/p/2046419.html
Copyright © 2011-2022 走看看