• POJ:2777-Count Color(线段树+状压)


    Count Color

    Time Limit: 1000MS Memory Limit: 65536K

    Description

    Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem.

    There is a very long board with length L centimeter, L is a positive integer, so we can evenly divide the board into L segments, and they are labeled by 1, 2, … L from left to right, each is 1 centimeter long. Now we have to color the board - one segment with only one color. We can do following two operations on the board:

    • “C A B C” Color the board from segment A to segment B with color C.
    • “P A B” Output the number of different colors painted between segment A and segment B (including).

    In our daily life, we have very few words to describe a color (red, green, blue, yellow…), so you may assume that the total number of different colors T is very small. To make it simple, we express the names of colors as color 1, color 2, … color T. At the beginning, the board was painted in color 1. Now the rest of problem is left to your.

    Input

    First line of input contains L (1 <= L <= 100000), T (1 <= T <= 30) and O (1 <= O <= 100000). Here O denotes the number of operations. Following O lines, each contains “C A B C” or “P A B” (here A, B, C are integers, and A may be larger than B) as an operation defined previously.

    Output

    Ouput results of the output operation in order, each line contains a number.

    Sample Input

    2 2 4
    C 1 1 2
    P 1 2
    C 2 2 2
    P 1 2

    Sample Output

    2
    1


    解题心得:

    1. 一看就是线段树,但是还加了状压,每一段区间用一个二进制来表示其涂抹情况,假如二进制的第一位为1代表第一种颜色涂抹了,然后父节点等于两个子节点的状态或起来,询问的区间用0去线段树中或,然后数1的个数就行了。区间更新的时候lazy标记一下,但是要注意的是颜色是直接覆盖。
    2. 读题眼贱了一下,没看到给的left端和right端可能是交换的,然后一直Runtime Error,怀疑人生啊。

    #include<stdio.h>
    #include<cstring>
    #include<iostream>
    using namespace std;
    const int maxn = 1e6+100;
    struct Bitree
    {
        int l,r;
        int co;
    } bitree[maxn<<2];
    int lazy[maxn<<2];
    int n,a,b,c,o,t,ans;
    
    void updata(int rt)//向上更新
    {
       bitree[rt].co = (bitree[rt<<1].co)|(bitree[rt<<1|1].co);//字节点或起来
    }
    
    void build_tree(int rt,int l,int r)//先初始化一棵树
    {
        bitree[rt].l = l;
        bitree[rt].r = r;
        bitree[rt].co |= 2;
        if(r == l)
            return ;
        int mid = (l + r)>>1;
        build_tree(rt<<1,l,mid);
        build_tree(rt<<1|1,mid+1,r);
        updata(rt);
    }
    
    void pushdown(int rt)//向下更新,注意lazy标记的转移方式就可以了
    {
        if(bitree[rt].l == bitree[rt].r || !lazy[rt])
            return ;
        bitree[rt<<1].co =  bitree[rt<<1|1].co = 0;
        bitree[rt<<1].co |= (1<<lazy[rt]);
        bitree[rt<<1|1].co |= (1<<lazy[rt]);
        lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt];
        lazy[rt] = 0;
    }
    
    void make_lazy(int rt,int l,int r,int L,int R)//区间更新,lazy标记
    {
        pushdown(rt);
        if(l == L && r == R)
        {
            lazy[rt] = c;
            bitree[rt].co = 0;
            bitree[rt].co |= (1<<c);
            return ;
        }
        int mid = (L + R) >> 1;
        if(mid >= r)
            make_lazy(rt<<1,l,r,L,mid);
        else if(mid < l)
            make_lazy(rt<<1|1,l,r,mid+1,R);
        else
        {
            make_lazy(rt<<1,l,mid,L,mid);
            make_lazy(rt<<1|1,mid+1,r,mid+1,R);
        }
        updata(rt);
    }
    
    void query(int rt,int l,int r,int L,int R)
    {
        pushdown(rt);
        if(L == l && R == r)
        {
            ans |= bitree[rt].co;//查询的时候用ans去将线段树中的状态或出来
            return ;
        }
        int mid = (L + R) >> 1;
        if(mid >= r)
            query(rt<<1,l,r,L,mid);
        else if(mid < l)
            query(rt<<1|1,l,r,mid+1,R);
        else
        {
            query(rt<<1,l,mid,L,mid);
            query(rt<<1|1,mid+1,r,mid+1,R);
        }
        updata(rt);
    }
    
    int SUM(int x)
    {
        int sum = 0;
        while(x)
        {
            if(x&1)
                sum++;
            x >>= 1;
        }
        return sum;
    }
    
    int main()
    {
        while(cin>>n>>t>>o)
        {
            memset(lazy,0,sizeof(lazy));
            memset(bitree,0,sizeof(bitree));
            build_tree(1,1,n);
            while(o--)
            {
                char s[10];
                scanf("%s",s);
                if(s[0] == 'C')
                {
                    scanf("%d%d%d",&a,&b,&c);
                    if(a>b)//注意交换啊,坑死了
                        swap(a,b);
                    make_lazy(1,a,b,1,n);
                }
                else if(s[0] == 'P')
                {
                    ans = 0;
                    scanf("%d%d",&a,&b);
                    if(a>b)
                        swap(a,b);
                    query(1,a,b,1,n);
                    ans = SUM(ans);//数最终有多少个1的个数
                    printf("%d
    ",ans);
                }
            }
        }
        return 0;
    }
    
  • 相关阅读:
    [总结] XPO (eXpress Persistent Objects) 学习总结一
    [总结]工作中常用的正则表达式,有了它事半功倍!
    用JS实现页面滚动位置保持的方法
    [总结]TLF论坛全功略,下载指南!
    Javascript里使用Dom操作Xml
    。NET构架相关资源
    [收藏]关于用Asp.Net论坛发帖软件的实现
    匹配Unicode字符的正则表达式(中文)
    [转贴]如何实现TreeView的双击事件?
    [转贴]客户端不装adobe reader,打开pdf文件的插件
  • 原文地址:https://www.cnblogs.com/GoldenFingers/p/9107220.html
Copyright © 2020-2023  润新知