zoukankan      html  css  js  c++  java
  • poj2777线段树+lazy思想

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

    这题更加让我理解线段树的结构了,特别是lazy思想的运用。

    事实上lazy思想就是个懒人的标记,若对于这个结点lazy标记为true,就代表不需要继续查找缩小的区间了。

    主要是在更新结点的地方,若填充整个区间时,标记lazy,则在下次其他的更新操作时,若结点为ture,则在更新操作中。

    为了控制标记,取消原来结点的标记false,表示此节点不可用,即该结点代表的线段中有不同的取值,然后在左右子树中标记lazy,直到填充整个区间。

    #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)                     //lazy思想,当一次取整块lr区间时,标记end,
        {                                   //然后下次操作遇到lr区间但不是目标区间时,消去该节点的end标记
            proot->end = false;             //为了简化后面的操作,直接给左右子树进行相应操作并同意标记end
            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;
    }
    


     

  • 相关阅读:
    Android(java)学习笔记15:匿名内部类实现多线程
    Android(java)学习笔记14:Java线程池
    Android(java)学习笔记13:线程组的概述和使用
    Android(java)学习笔记12:线程的状态转换图以及常见执行情况
    win2012R2打Windows8.1-KB2919355 问题
    win2012R2打Windows8.1-KB2919355 问题
    P2404
    P2404
    P2404
    抽签
  • 原文地址:https://www.cnblogs.com/amourjun/p/5134151.html
Copyright © 2011-2022 走看看