zoukankan      html  css  js  c++  java
  • POJ-2777Count Color 线段树+位移

    这道题对于我这样的初学者还是有点难度的不过2遍A了还是很开心,下面说说想法……
    Count Color
    Time Limit: 1000MS Memory Limit: 65536K
    Total Submissions: 40302 Accepted: 12161

    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:
    1. “C A B C” Color the board from segment A to segment B with color C.
    2. “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
    题目大意:
    往画板上染色,画板长L(1<=L<=100000)颜色共有T种(1<=T<=30)给你O条操作(1<=O<=100000)操作分两种
    (1)“C A B C”操作C:将【A,B】染成C色(开始时,画板都是颜色1)
    (2)“P A B”操作P:【A,B】范围内颜色种数

    (此题有个蛋疼的地方,读入的AB可能顺序颠倒...也是略坑)
    这道题用位移来做,如果染成t种颜色,就把颜色左移t-1位,位移运算在这道题里完美展现,所以以后还是得注重这种表示方法,了解多了,自然做题顺畅
    用二进制表示对应的区间涂了第几种颜色,这样每个区间除了延迟标记外,可以再开一个数组统计当前涂了哪几种颜色。这样就和一般的线段树一样了。
    (这种思想值得学习)
    

    最后再统计一下1的数目
    下面是代码:

    //这波位移非常的nice啊! 
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define maxl 100001
    int color[maxl<<2]={0},sum[maxl<<2]={0};
    
    void updata(int now)
    {
        sum[now]=sum[now<<1]|sum[now<<1|1]; 
    }//or
    
    void pushdown(int now)
    {
            if (color[now]!=0)
                {
                    color[now<<1]=color[now<<1|1]=color[now];
                    sum[now<<1]=color[now];
                    sum[now<<1|1]=color[now];
                    color[now]=0;
                }
    }
    
    void build(int l,int r,int now)
    {
        color[now]=1;
        if (l==r) return;
        int mid=(l+r)>>1;
        build(l,mid,now<<1);
        build(mid+1,r,now<<1|1);
        updata(now);
    }
    
    void change(int L,int R,int l,int r,int now,int newcolor)
    {
        if (L<=l && R>=r)
            {
                color[now]=1<<(newcolor-1);
                sum[now]=color[now];
                return;
    
            }//位移表示颜色 
        int mid=(l+r)>>1;   
        pushdown(now);
        if (L<=mid)
            change(L,R,l,mid,now<<1,newcolor);
        if (R>mid)
            change(L,R,mid+1,r,now<<1|1,newcolor);
        updata(now);
    }
    
    int query(int L,int R,int l,int r,int now)
    {
        if (L<=l && R>=r)
            return sum[now];
        pushdown(now);
        int mid=(l+r)>>1;
        int ans=0;
        if (L<=mid)
            ans=ans|query(L,R,l,mid,now<<1);
        if (R>mid)
            ans=ans|query(L,R,mid+1,r,now<<1|1);//要对结果取or 
        return ans;
    }
    
    int main()
    {
        int l,t,o;
        while(~scanf("%d%d%d",&l,&t,&o))
            {
                build(1,l,1);
                for (int i=1; i<=o; i++)
                    {
                        char command[2];
                        int left,right,data;
                        scanf("%s",&command);
                        if (command[0]=='C')
                            {
                                scanf("%d%d%d",&left,&right,&data);
                                if (left>right)
                                    {
                                        int temp=left;
                                        left=right;
                                        right=temp;
                                    }
                                change(left,right,1,l,1,data);
                            }
                        else
                            {
                                scanf("%d%d",&left,&right);
                                if (left>right)
                                    {
                                        int temp=left;
                                        left=right;
                                        right=temp;
                                    }
                                int ans=query(left,right,1,l,1);
                                int answer=0;
                                while (ans>0)
                                    {
                                        if (ans & 1)
                                            answer++;
                                        ans=ans>>1;
                                    }//这里表示颜色数 
                                printf("%d
    ",answer);
                            }
                    }
                printf("
    ");
            }
        return 0;
    
    }
  • 相关阅读:
    thinkphp tp5 常用 functions
    nginx配置虚拟机 vhost 端口号 域名 区分虚拟机
    thinkphp tp5 模板 引擎 字符串 截取 函数 省略 显示
    C++运算符重载
    c++纯虚函数
    c++面向对象模型---c++如何管理类,对象以及它们之间的联系
    c++多态
    c++友元函数
    c语言的函数指针
    c++两种字符串赋值方式 并介绍 C语言下遍历目录文件的方式
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5346257.html
Copyright © 2011-2022 走看看