题意 : 给你一L个点,一开始都涂成颜色1,然后有O次操作,C a b c 的话就是讲[a,b]涂成颜色c,若P a b,询问[a,b]区间不同颜色的数量。
思路 : 线段树,区间更新。(一开始没学过区间更新的,只会单点更新,结果更新复杂度为O(n),默默的TLE了几把)
开一个lazy数组,对应节点进行lazy操作,使得每次更新的时候不许要继续小区间更新下去了,而颜色覆盖的话使用位运算(因为颜色最多才30种)。另外此题要注意a 、b不一定是 a < b,要注意下的。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 100005;
int ans[MAXN<<2],lazy[MAXN<<2],n,m,T;
void Swap(int &a,int &b)
{
int t = a; a = b; b = t;
}
void push_down(int rt)
{
if (lazy[rt])
{
ans[rt<<1] = ans[rt<<1|1] = ans[rt];
lazy[rt<<1] = lazy[rt<<1|1] = 1;
lazy[rt] = 0;
}
}
void push_up(int rt)
{
ans[rt] = ans[rt<<1] | ans[rt<<1|1];
}
void update(int o,int L,int R,int l,int r,int col)
{
int M = (L + R) >> 1;
if (L >= l && R <= r)
{
ans[o] = col;
lazy[o] = 1;
return ;
}
push_down(o);
if (M >= l)update(o<<1,L,M,l,r,col);
if (r > M)update(o<<1|1,M+1,R,l,r,col);
push_up(o);
}
int query(int o,int L,int R,int l,int r)
{
int M = (L + R) >> 1, res = 0;
if (L >= l && R <= r) return ans[o];
push_down(o);
if (M >= l)res |= query(o<<1,L,M,l,r);
if (r > M)res |= query(o<<1|1,M+1,R,l,r);
return res;
}
int main()
{
int i;
memset(lazy,0,sizeof(lazy));
scanf("%d%d%d",&n,&T,&m);
for (i = 1;i <= 4 * n;i++)
{
ans[i] = 1;
}
while (m--)
{
char que[5];
int a,b,c;
scanf("%s%d%d",que,&a,&b);
if (a > b)Swap(a,b);
if (que[0] == 'C')
{
scanf("%d",&c);
update(1,1,n,a,b,1<<(c-1));
}
else
{
int res = query(1,1,n,a,b);
int cnt = 0;
for (i = 0;i < T;i++)if ((1<<i) & res)
cnt++;
printf("%d\n",cnt);
}
}
return 0;
}