poj 2777 Count Color

问题描述:http://poj.org/problem?id=2777

理解:

一道线段树的题。

统计一块木板上出现颜色的种类。相对纯粹和的累加还是不一样。涂上新的颜色会被覆盖掉,找不到合适的容器。

还有lazy算法,避免每一次搜索得把所有叶子节点遍历一遍

细节:

1."P A B" (here A, B, C are integers, and A may be larger than B) 意味着出现此种情况要交换

2.节点里还是不要Mid(),占空间。

解决办法:

1.用一个32位的整数,记录每一种颜色出现。解决覆盖可以用左右叶子节点  |  。计算颜色种数用移位>>。

2.两个操作

Color()这个函数的递归让我挺晕的。据我目前看来的递归函数,在调用自身之前常往下一步走,也就是“push up”, 调用自身之后,会反馈回来,

也就是“push down”。查询这个操作里,因为要用lazy算法,终止条件几乎都是,当前节点范围被s、e覆盖。

Output()这个函数里要返回颜色这个32位整数。在最后一个判断条件里是用符号 | 进行种数的累加,而不是单纯的加和,我就wa在这里了。

3.标记flag为1的时候表示只有当前区间只有一种颜色(可以选择push down);为0的时候就已经有多种颜色了。


代码:

#include <iostream>
#include <cstdio>

#define N 100050

using namespace std;

struct Node
{
    int L, R, flag;
    int C;    //32位整数
    int Mid()
    {
        return (L + R)/2;
    }
} tree[N * 4];

int amount(int c)
{
    int a = 0;
    while(c != 0)
    {
        if((c & 1) == 1)
        {
            a++;
        }
        c >>= 1;
    }
    return a;
}
/*
void print(int root)
{
    cout << tree[root].L << " " << tree[root].R << endl;
    cout << tree[root].flag << endl;
    cout << amount(tree[root].C) << endl << endl;
}
*/

void BuildTree(int root, int L, int R)
{
    tree[root].L = L;
    tree[root].R = R;
    tree[root].C = 1;
    tree[root].flag = 1;//

    if(L != R)
    {
        BuildTree(root * 2 + 1, L, (L + R)/2);
        BuildTree(root * 2 + 2, (L + R)/2 + 1, R);
    }
}

void color(int root, int s, int e, int t)
{
    if(s <= tree[root].L && tree[root].R <= e)
    {
        tree[root].C = (1 << (t - 1));
        tree[root].flag = 1;
        //print(root);
        return;
    }
    if(tree[root].flag)
    {
        tree[root * 2 + 1].C = tree[root * 2 + 2].C = tree[root].C;
        tree[root * 2 + 1].flag = tree[root * 2 + 2].flag = 1;
        tree[root].flag = 0;
    }

    if(e <= tree[root].Mid())
    {
        color(root * 2 + 1, s, e, t);
    }
    else if(s > tree[root].Mid())
    {
        color(root * 2 + 2, s, e, t);
    }
    else
    {
        color(root * 2 + 1, s, tree[root].Mid(), t);
        color(root * 2 + 2, tree[root].Mid() + 1, e, t);
    }
    tree[root].C = tree[root * 2 + 1].C | tree[root * 2 + 2].C;
    tree[root].flag = 0;
}

int output(int root, int s, int e)
{
    if((s <= tree[root].L && tree[root].R <= e) || tree[root].flag)
    {
        return tree[root].C;
    }

    if(e <= tree[root].Mid())
    {
        return output(root * 2 + 1, s, e);
    }
    else if(s > tree[root].Mid())
    {
        return output(root * 2 + 2, s, e);
    }
    else
    {
        return output(root * 2 + 1, s, tree[root].Mid()) | output(root * 2 + 2, tree[root].Mid() + 1, e);
    }

}

int main()
{
    int L, T, O;
    scanf("%d%d%d", &L, &T, &O);
    //cin >> L >> T >> O;

    BuildTree(0, 1, L);

    for(int i = 0; i < O; i++)
    {
        char c;
        int s, e, t;

        getchar();
        scanf("%c", &c);
        //cin >> c;
        if(c == 'C')
        {
            scanf("%d%d%d", &s, &e, &t);
            //cin >> s >> e >> t;
            color(0, s, e, t);
            /*
            for(int i = 0; i <  L + 1; i++)
            {
                print(i);
            }
            */

        }
        else if(c == 'P')
        {
            scanf("%d%d", &s, &e);
            //cin >> s >> e;
            if(s > e)
                swap(s, e);

            printf("%d\n", amount(output(0, s, e)));
            //cout << A << endl;
        }
    }

    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值