解题思路
这道题看上去是一道普通的区间更新问题,但入手还是挺多坑的。
因为所要查询的是给定区间内不同颜色的个数,这就需要在每一层节点都要保存该区间的涂色情况,如果仅仅记录个数,是无法在较上一层进行汇总的,如果在每一个节点都用数组进行存储,那么对空间和运算时间都是很消耗的。
所幸颜色种类比较少,所以我们可以像函数中的标志参数那样,用不同位上的 1 来表示不同的颜色,(即 1 表示 1,10 表示 2,100 表示 3,1000 表示 4……)将两个数按位或起来,就可以将信息进行汇总,30 种颜色,用 int 就可以存下来。
其他的类似于基本的区间更新操作。需要注意的是涂色是覆盖问题,操作有先后 顺序 。当更新当前区间时也需要将信息更新到下一层,不然操作可能进行覆盖。
另外此题中查询区间 [a,b], a 可能大于 b。
代码
#include <iostream>
#include <cstdio>
#define lson tree[root].ls
#define rson tree[root].rs
using namespace std;
struct node
{
int l, r; // 左右区间
int ls, rs; // 左右子树的位置
int pColor; // 涂色动作
int sColor; // 当前区间颜色汇总
}tree[200100];
int nCount = 1;
void build(int root, int l, int r)
{
// 初始化
tree[root].l = l;
tree[root].r = r;
tree[root].pColor = 0;
tree[root].sColor = 1;
if(l!=r)
{
// 递归构建
lson = ++nCount;
build(lson, l, (l+r)/2);
rson = ++nCount;
build(rson, (l+r)/2+1, r);
}
}
void update(int root, int l, int r, int color)
{
if(tree[root].l==l && tree[root].r==r)
{
// 更新操作
tree[root].pColor = color;
tree[root].sColor = color;
}
else
{
// push_down操作
if(tree[root].pColor)
{
tree[lson].sColor = tree[rson].sColor =
tree[lson].pColor = tree[rson].pColor = tree[root].pColor;
tree[root].pColor = 0;
}
int mid = (tree[root].l + tree[root].r) / 2;
// 递归操作
if(r<=mid) update(lson, l, r, color);
else if(l>=(mid+1)) update(rson, l, r, color);
else
{
update(lson, l, mid, color);
update(rson, mid+1, r, color);
}
// 信息汇总
tree[root].sColor = tree[lson].sColor | tree[rson].sColor;
}
}
void query(int root, int l, int r, int &ans)
{
if(tree[root].l==l && tree[root].r==r)
{
ans = ans | tree[root].sColor;
}
else
{
// push_down 操作,将当前信息更新到下一层
if(tree[root].pColor)
{
tree[lson].sColor = tree[rson].sColor =
tree[lson].pColor = tree[rson].pColor = tree[root].pColor;
tree[root].pColor = 0;
}
int mid = (tree[root].l+tree[root].r) / 2;
if(r<=mid) query(lson, l, r, ans);
else if(l>=(mid+1)) query(rson, l, r, ans);
else
{
query(lson, l, mid, ans);
query(rson, mid+1, r, ans);
}
}
}
// 从结果中读出 1 的个数
int re(int num)
{
int ans = 0;
while(num>0)
{
if(num&1) ans++;
num >>= 1;
}
return ans;
}
int main()
{
int l, t, o;
int a, b, c;
char op[10];
scanf("%d%d%d", &l, &t, &o);
build(1, 1, l);
for(int i=1; i<=o; i++)
{
scanf("%s", op);
if(op[0]=='C')
{
scanf("%d%d%d", &a, &b, &c);
if(a>b) swap(a, b);
update(1, a, b, 1<<(c-1));
}
else
{
int ans = 0;
scanf("%d%d", &a, &b);
if(a>b) swap(a, b);
query(1, a, b, ans);
printf("%d\n", re(ans));
}
}
return 0;
}