传送门:点击打开链接
线段树入门题。
题目大意:
给定一个区间,初始染色值都是1,一共有最多30种颜色。
有2种操作:
1:区间覆盖。将整个区间覆盖为颜色C。
2:区间查询。查询(l,r)区间内颜色的数目。
解题思路:
首先,颜色的种类数只有最多30种那么就可以用INT的二进制来表示。
然后pushup操作就只需要将两个下方的区间的颜色值或起来,就是上方区间的颜色值。
pushdown操作就是简单的区间覆盖。
注意:这个题有坑点,虽然题目告诉了。区间可能是反的。也就是 l > r
#include <cstdio>
#define maxn 100010
struct Node
{
int l,r;
int c,sum;
}tree[maxn<<2];
inline void pushup(int id)
{
tree[id].sum = tree[id<<1].sum | tree[id<<1|1].sum;
}
inline void pushdown(int id)
{
if(tree[id].c)
{
tree[id<<1].c = tree[id<<1|1].c = tree[id].c;
tree[id<<1].sum = tree[id].c;
tree[id<<1|1].sum =tree[id].c;
tree[id].c = 0;
}
}
void build(int id,int l,int r)
{
tree[id].l = l;
tree[id].r = r;
tree[id].c = 0;
if(l == r)
{
tree[id].sum = 1;
return ;
}
int mid = (l+r)>>1;
build(id<<1,l,mid);
build(id<<1|1,mid+1,r);
pushup(id);
}
void op(int id,int l,int r,int c)
{
if(tree[id].l >= l && tree[id].r <= r)
{
tree[id].sum = c;
tree[id].c = c;
return ;
}
pushdown(id);
int mid = (tree[id].l + tree[id].r) >>1;
if(l <= mid) op(id<<1,l,r,c);
if(mid < r) op(id<<1|1,l,r,c);
pushup(id);
}
int query(int id,int l,int r)
{
if(tree[id].l >= l && tree[id].r <= r)
{
return tree[id].sum;
}
pushdown(id);
int mid = (tree[id].l + tree[id].r)>>1;
int res = 0;
if(l <= mid) res |= query(id<<1,l,r);
if(mid < r) res |= query(id<<1|1,l,r);
return res;
}
int main()
{
int n,t,q;
while(scanf("%d %d %d",&n,&t,&q) != EOF)
{
build(1,1,n);
while(q--)
{
char s[10];
scanf("%s",s);
if(s[0] == 'C')
{
int l,r,c;
scanf("%d %d %d",&l,&r,&c);
if(l > r)
{
int t = l;
l = r;
r = t;
}
op(1,l,r,(1<<(c-1)));
}
else
{
int l,r;
scanf("%d %d",&l,&r);
if(l > r)
{
int t = l;
l = r;
r = t;
}
int res = query(1,l,r);
int ans = 0;
while(res)
{
ans += (res&1);
res>>=1;
}
printf("%d\n",ans);
}
}
}
return 0;
}