题目链接:[POJ 2777]Count Color[线段树区间更新查询]
题意分析:
给出一个长为L的长板,划分成L个单元,每个单元初始时颜色为1。先给出O个操作,包含更改区间l,r为颜色c和查询区间l,r中有多少种不同的颜色。颜色数不超过30个。
解题思路:
题目需要查询的是区间中有多少种不同的颜色,而颜色数又不超过30个,我们可以用二进制来表示一个区间中拥有的颜色,更新的时候等于两个子区间的或,然后查询有多少个1就行了。
还是得郑重推荐下这个函数XD
__builtin_popcount() //统计二进制中1的个数
个人感受:
debug了整整两个小时,莫名A,然后找数据,找原因,最后发现是二进制的表示上出了问题= =
具体代码如下:
#include<iostream>
#include<cstdio>
#define root 1, n, 1
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define pr(x) cout << #x << '=' << (x) << '\n';
using namespace std;
const int MAXN = 1e5 + 111;
int color[MAXN << 2], add[MAXN << 2];
void push_up(int rt)
{
color[rt] = color[rt << 1] | color[rt << 1 | 1];
}
void push_down(int rt, int l, int r)
{
if (add[rt] != -1)
{
add[rt << 1] = add[rt << 1 | 1] = add[rt];
color[rt << 1] = color[rt << 1 | 1] = 1 << add[rt];
add[rt] = -1;
}
}
void build(int l, int r, int rt)
{
add[rt] = -1;
if (l == r)
{
color[rt] = 1;
return;
}
int m = l + r >> 1;
build(lson);
build(rson);
push_up(rt);
}
int query(int L, int R, int l, int r, int rt)
{
if (L <= l && r <= R)
{
return color[rt];
}
push_down(rt, l, r);
int ret = 0;
int m = l + r >> 1;
if (L <= m) ret |= query(L, R, lson);
if (m < R) ret |= query(L, R, rson);
return ret;
}
void update(int L, int R, int val, int l, int r, int rt)
{
if (L <= l && r <= R)
{
add[rt] = val;
color[rt] = 1 << val;
return;
}
push_down(rt, l, r);
int m = l + r >> 1;
if (L <= m) update(L, R, val, lson);
if (m < R) update(L, R, val, rson);
push_up(rt);
}
int main()
{
int n, t, o; scanf("%d%d%d", &n, &t, &o);
build(root);
char op[2];
int l, r, col;
while (o --)
{
scanf("%s %d %d", op, &l, &r);
if (l > r) swap(l, r);
if (op[0] == 'C')
{
scanf("%d", &col);
update(l, r, col - 1, root); // 1 << 0 表示第一种颜色
}
else
{
printf("%d\n", __builtin_popcount(query(l, r, root)));
}
}
return 0;
}