Description
Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem.
There is a very long board with length L centimeter, L is a positive integer, so we can evenly divide the board into L segments, and they are labeled by 1, 2, ... L from left to right, each is 1 centimeter long. Now we have to color the board - one segment with only one color. We can do following two operations on the board:
1. "C A B C" Color the board from segment A to segment B with color C.
2. "P A B" Output the number of different colors painted between segment A and segment B (including).
In our daily life, we have very few words to describe a color (red, green, blue, yellow…), so you may assume that the total number of different colors T is very small. To make it simple, we express the names of colors as color 1, color 2, ... color T. At the beginning, the board was painted in color 1. Now the rest of problem is left to your.
There is a very long board with length L centimeter, L is a positive integer, so we can evenly divide the board into L segments, and they are labeled by 1, 2, ... L from left to right, each is 1 centimeter long. Now we have to color the board - one segment with only one color. We can do following two operations on the board:
1. "C A B C" Color the board from segment A to segment B with color C.
2. "P A B" Output the number of different colors painted between segment A and segment B (including).
In our daily life, we have very few words to describe a color (red, green, blue, yellow…), so you may assume that the total number of different colors T is very small. To make it simple, we express the names of colors as color 1, color 2, ... color T. At the beginning, the board was painted in color 1. Now the rest of problem is left to your.
Input
First line of input contains L (1 <= L <= 100000), T (1 <= T <= 30) and O (1 <= O <= 100000). Here O denotes the number of operations. Following O lines, each contains "C A B C" or "P A B" (here A, B, C are integers, and A may be larger than B) as an operation defined previously.
Output
Ouput results of the output operation in order, each line contains a number.
Sample Input
2 2 4 C 1 1 2 P 1 2 C 2 2 2 P 1 2
Sample Output
2 1
Source
题目大意:有一段长度为L的板,分为L段。对这些段进行一些列染色询问操作如下:
C x y z:把x,y之间的段染成z颜色。
P x y:询问x,y之间有多少种颜色。
L最大100000,询问最多100000,但颜色最多30种。
观察颜色,不大于30,也就是说可以用longint储存下来颜色出现情况。这样,就可以用线段树维护了。
每一个线段树上的节点开一个a数组记录它所代表的段上面颜色的出现情况。再开一个p数组,用来标记,p[i]为true则一整段为一种颜色,下次修改询问的时候往下推标记,这样可以省很多时间。
对于修改时候的更新,只要把两个儿子的a值进行or运算赋到当前节点的a值上即可。
对于询问,也用or运算得到颜色出现情况color,最后计数1的个数。这里可以用树状数组里面lowbit的求法,用一个while不断地从color中减去lowbit(color)直到color为0。这样减了几次,就有几种不同的颜色。
这题RE了好多次,结果再看题目,竟然有一句‘and A
may be larger than B’!!!瞬间无语了。。。每一次读入还要判断头尾端点的大小关系,进行调换。。。有种被阴的感觉。。。还有,每一段的初始颜色是1。
AC CODE
program pku_2777;
var a:array[1..600000] of longint;
p:array[1..600000] of boolean;
color,s,t,z,i,n,o:longint;
command:char;
//============================================================================
procedure change(be,en,now:longint);
var mid:longint;
begin
if (be>=s) and (en<=t) then
begin
a[now]:=color;
p[now]:=true; exit;
//打标记。
end;
if p[now] then
//推标记。
begin
a[now shl 1]:=a[now]; p[now shl 1]:=true;
a[now shl 1+1]:=a[now]; p[now shl 1+1]:=true;
p[now]:=false;
//一定记得要取消标记。
end;
mid:=(be+en) shr 1;
if t<=mid then change(be,mid,now shl 1) else
if s>mid then change(mid+1,en,now shl 1+1) else
begin
change(be,mid,now shl 1);
change(mid+1,en,now shl 1+1);
end;
a[now]:=a[now shl 1] or a[now shl 1+1];
//递归回来要更新a值。
end;
//============================================================================
procedure ask(be,en,now:longint);
var mid:longint;
begin
if (be>=s) and (en<=t) then
begin
color:=color or a[now];
//在color中加入当前段的颜色。or很好用的说。。。
exit;
end;
if p[now] then
begin
a[now shl 1]:=a[now]; p[now shl 1]:=true;
a[now shl 1+1]:=a[now]; p[now shl 1+1]:=true;
p[now]:=false;
end;
mid:=(be+en) shr 1;
if t<=mid then ask(be,mid,now shl 1) else
if s>mid then ask(mid+1,en,now shl 1+1) else
begin
ask(be,mid,now shl 1);
ask(mid+1,en,now shl 1+1);
end;
end;
//============================================================================
begin
fillchar(p,sizeof(p),0);
readln(n,t,o);
a[1]:=1; p[1]:=true;
//本来想for一遍或调用change的,但是标记这么好用的东西不用白不用。
for i:=1 to o do
begin
read(command);
if command='C' then
begin
readln(s,t,z);
if s>t then
//调换头尾端点,用color是因为懒得开空间了。。。
begin
color:=s; s:=t; t:=color;
end;
color:=1 shl (z-1);
//把颜色转成10进制。
change(1,n,1);
end else
begin
readln(s,t);
if s>t then
begin
color:=s; s:=t; t:=color;
end;
color:=0; ask(1,n,1);
z:=color; color:=0;
while z>0 do
//树状数组的lowbit求法。
begin
z:=z-z and (-z);
inc(color);
end; writeln(color);
end;
end;
end.
var a:array[1..600000] of longint;
//============================================================================
procedure change(be,en,now:longint);
var mid:longint;
begin
end;
//============================================================================
procedure ask(be,en,now:longint);
var mid:longint;
begin
end;
//============================================================================
begin
end.