题意:有一个长板子,多次操作,有两种操作,第一种是给从a到b那段染一种颜色c,另一种是询问a到b有多少种不同的颜色。
这题更加让我理解线段树的结构了,特别是lazy思想的运用。
事实上lazy思想就是个懒人的标记,若对于这个结点lazy标记为true,就代表不需要继续查找缩小的区间了。
主要是在更新结点的地方,若填充整个区间时,标记lazy,则在下次其他的更新操作时,若结点为ture,则在更新操作中。
为了控制标记,取消原来结点的标记false,表示此节点不可用,即该结点代表的线段中有不同的取值,然后在左右子树中标记lazy,直到填充整个区间。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
#define maxn 100004
struct Node
{
int color;
int l, r;
Node *pleft, *pright;
bool end;
} tree[maxn * 3];
int n, t, o, ncount;
void buildtree(Node *proot, int l, int r)
{
proot->l = l;
proot->r = r;
proot->color = 1;
proot->end = true;
if (l == r)
return;
int mid = (l + r) / 2;
ncount++;
proot->pleft = tree + ncount;
ncount++;
proot->pright = tree + ncount;
buildtree(proot->pleft, l, mid);
buildtree(proot->pright, mid + 1, r);
}
void paint(Node *proot, int l, int r, int color)
{
if (proot->l == l && proot->r == r)
{
proot->end = true;
proot->color = color;
return;
}
if (proot->end) //lazy思想,当一次取整块lr区间时,标记end,
{ //然后下次操作遇到lr区间但不是目标区间时,消去该节点的end标记
proot->end = false; //为了简化后面的操作,直接给左右子树进行相应操作并同意标记end
proot->pleft->color = proot->color;
proot->pleft->end = true;
proot->pright->color = proot->color;
proot->pright->end = true;
}
int mid = (proot->l + proot->r) / 2;
if (r <= mid)
paint(proot->pleft, l, r, color);
else if(l > mid)
paint(proot->pright, l, r, color);
else
{
paint(proot->pleft, l, mid, color);
paint(proot->pright, mid +1, r, color);
}
proot->color = proot->pleft->color | proot->pright->color; //位运算
}
int query(Node *proot, int l, int r)
{
if (proot->end) //若父节点已经被标记.便不需要往下找
return proot->color;
if (proot->l == l && proot->r == r)
return proot->color;
int mid = (proot->l + proot->r) / 2;
if (r <= mid)
return query(proot->pleft, l, r);
else if(l > mid)
return query(proot->pright, l, r);
return query(proot->pleft, l, mid) | query(proot->pright, mid + 1, r);
}
int countbit(int a)
{
int x = 1;
int ret = 0;
for (int i = 0; i < 32; i++, x <<= 1)
if (x & a)
ret++;
return ret;
}
int main()
{
// freopen("t.txt", "r", stdin);
ncount = 0;
scanf("%d%d%d", &n, &t, &o);
getchar();
buildtree(tree, 1, n);
for (int i = 0; i < o; i++)
{
char order;
int l, r, c;
scanf("%c", &order);
if (order == 'C')
{
scanf("%d%d%d", &l, &r, &c);
if (l > r)
swap(l, r);
paint(tree, l, r, 1 << (c - 1));
}
else
{
scanf("%d%d", &l, &r);
if (l > r)
swap(l, r);
printf("%d\n", countbit(query(tree, l, r)));
}
getchar();
}
return 0;
}