题目大意
有一个长为L的甲板,能把他平均分为L段,每一段能有不同的颜色,为了简便,颜色可以数字(1,2,…T)代表不同的颜色。初始的时候L段均为颜色1。我们能对这个分为L段的甲板做两种操作:
1. C X Y Z,C代表操作 把区间[X,Y]中所有段变为Z颜色
2. P X Y ,P代表操作,表示查询出[X,Y]中有几种不同的颜色
输入:第一行输入三个整数L(甲板的长度),T(颜色的种类),Q(操作的次数)
下面的Q行输入的是操作,遇到查询操作的时候输出
输出:当执行P操作的时候输出该区间不同的颜色种类
解题思路
线段树的区间更新,用到了延时标记。
还有一个就是如何标记不同的颜色,因为每一种颜色的序号都是不同的,所有可以用位运算的方法,1左移颜色的序号减一位,就代表第几号颜色,初始化的时候颜色均为1。然后通过左后孩子颜色进行与运算得到该元素的颜色数量,颜色数量等于这个颜色中1的位数。
最重要的一点就是,这道题中X是可以大于Y的,这里要注意一下
AC代码
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 200005;
typedef long long LL; //lld
LL ans;
struct Node{
int left;
int right;
int color;
int addMark;
int mid()
{
return (left+right)>>1;
}
}tree[MAXN*4];
void pushUp(int rt)
{
tree[rt].color = ( (tree[rt<<1].color) | (tree[rt<<1|1].color)); //通过左右孩子节点的color得到该节点颜色的数量
}
void buildTree(int left,int right,int rt)
{
tree[rt].left = left;
tree[rt].right= right;
tree[rt].addMark = -1;
tree[rt].color = 1;
if(left == right)
{
return ;
}
int mid = tree[rt].mid();
buildTree(left,mid,rt<<1);
buildTree(mid+1,right,rt<<1|1);
pushUp(rt);
}
void PushDown(int rt)
{
if(tree[rt].addMark != -1)
{
tree[rt<<1].addMark = tree[rt<<1|1].addMark = tree[rt].addMark;
tree[rt<<1].color = tree[rt<<1|1].color = tree[rt].color;
tree[rt].addMark = -1;
}
}
void queryTree(int left,int right,int rt,int L,int R)
{
if(left>=L && right<=R)
{
ans |= tree[rt].color;
return ;
}
PushDown(rt);
int mid = tree[rt].mid();
if(L<=mid)
queryTree(left,mid,rt<<1,L,R);
if(R>mid)
queryTree(mid+1,right,rt<<1|1,L,R);
}
void updateTree(int left,int right,int rt,int L,int R,int color)
{
if(left>=L && right<=R)
{
tree[rt].addMark = color;
tree[rt].color = color;
return ;
}
PushDown(rt);
int mid = tree[rt].mid();
if(L<=mid)
updateTree(left,mid,rt<<1,L,R,color);
if(R>mid)
updateTree(mid+1,right,rt<<1|1,L,R,color);
pushUp(rt);
}
LL tenToLen(LL ans) //计算该数中有多少个1,就代表有几种颜色
{
int len = 0;
while(ans)
{
if(ans%2)
len++;
ans/=2;
}
return len;
}
int main()
{
int t,n,o;
int a,b,c;
char ch;
scanf("%d%d%d",&n,&t,&o);
buildTree(1,n,1);
while(o--)
{
getchar();
scanf("%c",&ch);
if(ch == 'C')
{
scanf("%d%d%d",&a,&b,&c);
updateTree(1,n,1,min(a,b),max(a,b),1<<(c-1));//用到了min函数和max保证区间是从大到小
}
else if(ch == 'P')
{
scanf("%d%d",&a,&b);
ans = 0;
queryTree(1,n,1,min(a,b),max(a,b));
printf("%lld\n",tenToLen(ans));
}
}
return 0;
}