题目大意:在一块长L厘米的木板上着色(木板分为长度相等的L块),有T种不同颜色,现在可以有两种操作C和P,一是“C A B C”意思是A到B木板着C颜色,二是“P A B”意思是输出A到B木板上着的不同颜色的种类数,最开始时木板整个被涂上1号颜色。
输入:L T O(O是操作个数) (1 <= L <= 100000) (1 <= T <= 30) (1 <= O <= 100000)
操作(共O个)
输出:按顺序输出P操作的输出结果
分析:线段树每个结点维护区间着的颜色号。
首先建好线段树,开始时每个区间都着1号色。然后根据输入判断是C还是P。
C操作就将A到B着C号色,也就是update线段树:如果当前区间对应要着色的区间,就直接着色返回;如果当前区间本来就已经是C号色则直接返回;如果当前区间只有一种颜色(.num!=-1),就要将它的两个子区间也更新成它的颜色,并且修改它的.num标记为-1,表示当前区间有多种颜色,因为它的某一段(A到B)被着了C号色。接下来就是递归update子区间。
P操作就查询搜索A到B的颜色个数,也就是search线段树:查询时记录此时线段树中有几种颜色被使用过,vis[]数组就是为了记录这个,我们在搜索到一个只有一个颜色的区间时,就标记这个区间的颜色为1,未使用过的颜色标记为0。接下来就是递归搜索。
这道题要注意搜不能一直更新到线段树叶节点,更新到符合的区间(两种return情况)就返回,否则会超时。
有的代码没有用到vis数组,而是直接或运算得出颜色种类数。
代码:转载自https://www.2cto.com/kf/201512/454627.html
#include <iostream>
#include <cstdio>
#include <cstring>
#include
#include <cmath>
#include <queue>
using namespace std;
struct node
{
int
l,r;
int
num;
} s[
400010
];
int
vis[
35
];
void
InitTree(
int
l,
int
r,
int
k)
{
s[k].l=l;
s[k].r=r;
s[k].num=
1
;
int
mid=(l+r)/
2
;
if
(l==r)
return
;
InitTree(l,mid,
2
*k);
InitTree(mid+
1
,r,
2
*k+
1
);
}
void
UpdataTree(
int
l,
int
r,
int
c,
int
k)
{
if
(s[k].l==l&&s[k].r==r)
{
s[k].num=c;
return
;
}
if
(s[k].num==c)
return
;
if
(s[k].num!=-
1
)
//如果所查询的区间不是多种颜色
{
s[
2
*k].num=s[k].num;
//更新区间的颜色
s[
2
*k+
1
].num=s[k].num;
s[k].num=-
1
;
//-1表示该区间有多种颜色
}
int
mid=(s[k].l+s[k].r)/
2
;
if
(l>mid)
UpdataTree(l,r,c,
2
*k+
1
);
else
if
(r<=mid)
UpdataTree(l,r,c,
2
*k);
else
{
UpdataTree(l,mid,c,
2
*k);
UpdataTree(mid+
1
,r,c,
2
*k+
1
);
}
}
void
SearchTree(
int
l,
int
r,
int
k)
{
if
(s[k].num!=-
1
)//这段区间只用了一种颜色
{
vis[s[k].num]=
1
;//标记使用过这种颜色
return
;
}
int
mid=(s[k].l+s[k].r)/
2
;
if
(r<=mid)
SearchTree(l,r,
2
*k);
else
if
(l>mid)
SearchTree(l,r,
2
*k+
1
);
else
{
SearchTree(l,mid,
2
*k);
SearchTree(mid+
1
,r,
2
*k+
1
);
}
}
int
main()
{
int
l,t,o,ans;
while
(~scanf(
"%d%d%d"
,&l,&t,&o))
{
InitTree(
1
,l,
1
);
while
(o--)
{
char
ch;
int
a,b,c;
getchar();
scanf(
"%c"
,&ch);
if
(ch==
'C'
)
{
scanf(
"%d%d%d"
,&a,&b,&c);
if
(a>b)
swap(a,b);
UpdataTree(a,b,c,
1
);
}
else
{
scanf(
"%d%d"
,&a,&b);
if
(a>b)
swap(a,b);
memset(vis,
0
,sizeof(vis));
SearchTree(a,b,
1
);
ans=
0
;
for
(
int
i=
1
; i<=t; i++)//判断所有颜色中使用哪几种就能算出颜色个数了
if
(vis[i]==
1
)
ans++;
printf (
"%d\n"
,ans);
}
}
}
return
0
;
}