POJ_2777
这个题目在用线段树自顶向下处理的时候,需要对每个节点做两个标记,一个是当前区间包含的颜色,另一个就是lazy标记。
lazy标记是为了节省更新子节点颜色的时间,也就是在染色时没有必要立刻更新子节点的颜色,而是在自顶向下查询时如果发现需要更新子节点,那么再将lazy标记不断下传并更新子节点,这样就节省了时间。
对于颜色的表示,由于染色种类较少,因此可以用二进制数来表示每个区间的染色情况。
#include<stdio.h>
#include<string.h>
#define MAXD 100010
int L, T, O, M, res, tree[4 * MAXD], left[4 * MAXD], right[4 * MAXD], lazy[4 * MAXD];
char op[5];
void init()
{
int i, j;
for(M = 1; M < L + 2; M <<= 1);
for(i = 0, j = M; i < M; i ++, j ++)
left[j] = right[j] = i;
for(i = M - 1; i > 0; i --)
{
left[i] = left[2 * i];
right[i] = right[2 * i + 1];
}
for(i = 2 * M - 1; i > 0; i --)
{
tree[i] = (1 << 1);
lazy[i] = 0;
}
}
void paint(int cur, int a, int b, int col)
{
if(lazy[cur] && cur < M)
{
lazy[cur] = 0;
lazy[2 * cur + 1] = lazy[2 * cur] = 1;
tree[2 * cur + 1] = tree[2 * cur] = tree[cur];
}
if(left[cur] >= a && right[cur] <= b)
{
tree[cur] = (1 << col);
lazy[cur] = 1;
for(int i = cur; i ^ 1; i >>= 1)
tree[i >> 1] = (tree[i] | tree[i ^ 1]);
return ;
}
if(left[2 * cur] <= b && right[2 * cur] >= a)
paint(2 * cur, a, b, col);
if(left[2 * cur + 1] <= b && right[2 * cur + 1] >= a)
paint(2 * cur + 1, a, b, col);
}
void search(int cur, int a, int b)
{
if(lazy[cur] && cur < M)
{
lazy[cur] = 0;
lazy[2 * cur + 1] = lazy[2 * cur] = 1;
tree[2 * cur + 1] = tree[2 * cur] = tree[cur];
}
if(right[cur] <= b && left[cur] >= a)
{
res |= tree[cur];
return ;
}
if(left[2 * cur] <= b && right[2 * cur] >= a)
search(2 * cur, a, b);
if(left[2 * cur + 1] <= b && right[2 * cur + 1] >= a)
search(2 * cur + 1, a, b);
}
void solve()
{
int i, j, k, A, B, C, num;
scanf("%s", op);
if(op[0] == 'C')
{
scanf("%d%d%d", &A, &B, &C);
if(A > B)
{
k = A;
A = B;
B = k;
}
paint(1, A, B, C);
}
else
{
scanf("%d%d", &A, &B);
if(A > B)
{
k = A;
A = B;
B = k;
}
res = 0;
search(1, A, B);
num = 0;
for(i = 1; i <= 30; i ++)
if(res & (1 << i))
num ++;
printf("%d\n", num);
}
}
int main()
{
while(scanf("%d%d%d", &L, &T, &O) == 3)
{
init();
for(int i = 0; i < O; i ++)
solve();
}
return 0;
}