分析:常规思想的一个个数据更新,会超时,更新速度问题可以想到线段树。而如果用最普通的线段树一样会超时,而由此我们可以用到线段树里面的lazy思想。线段树区间更新,可以不用更新到子节点(因为以后可能用不到,如果下次需要用,则下次把这一次的更新,这就体现了lazy的思想)。此题的颜色,我们可以用位运算来实现,每一位的是否为1,表明有多少颜色。采用lazy标记,更新到满足条件的区间,如果下一次有用到该区间下的子区间,通过lazy标记来更新出上次更新的结果。lazy的标记多种多样,而此题的cover就是其中一种,具体的内容读者自行体会
#include <iostream>
#include<stdio.h>
using namespace std;
const int MAX=100010;
int color;
typedef struct no
{
int left,right;
int color;
bool cover;
};
no node[4*MAX];
void Swap(int &a,int &b)
{
if(a>b)
{
int t=a;
a=b;
b=t;
}
}
void build(int l,int r,int id)
{
node[id].left=l;
node[id].right=r;
node[id].color=1;
node[id].cover=false;
if(l==r)
return;
int mid=(l+r)/2;
int cur1=id*2;
int cur2=id*2+1;
build(l,mid,cur1);
build(mid+1,r,cur2);
}
void update(int id,int a,int b,int c)
{
if(node[id].left==a&&node[id].right==b)
{
node[id].cover=true;
node[id].color=1<<(c-1);
return;
}
if(node[id].cover==true)
{
int cur1=id*2,cur2=id*2+1;
node[cur1].color=node[id].color;
node[cur1].cover=true;
node[cur2].color=node[id].color;
node[cur2].cover=true;
node[id].cover=false;
}
int mid=(node[id].left+node[id].right)/2;
if(mid>=b)
update(id*2,a,b,c);
else
if(mid<a)
update(id*2+1,a,b,c);
else
{
update(id*2,a,mid,c);
update(id*2+1,mid+1,b,c);
}
node[id].color=node[id*2].color|node[id*2+1].color;
}
void query(int id,int a,int b,int &ans)
{
if(node[id].cover||(node[id].left==a&&node[id].right==b))
{
ans|=node[id].color;
return ;
}
int mid=(node[id].left+node[id].right)/2;
if(mid<a)//搜索右子树
query(id*2+1,a,b,ans);
else
if(mid>=b)//搜索左子树
query(id*2,a,b,ans);
else
{
query(id*2,a,mid,ans);
query(id*2+1,mid+1,b,ans);
}
}
int sum(int s)
{
int ans=0;
while(s)
{
if(s&1)
ans++;
s/=2;
}
return ans;
}
int main()
{
int L,T,O;
scanf("%d%d%d",&L,&T,&O);
build(1,L,1);
char ch;
int a,b,c;
for(int i=0;i<O;i++)
{
cin>>ch;
if(ch=='C')
{
scanf("%d%d%d",&a,&b,&c);
Swap(a,b);
update(1,a,b,c);
}
else
{
color=0;
scanf("%d%d",&a,&b);
Swap(a,b);
int ans=0;
query(1,a,b,ans);
printf("%d\n",sum(ans));
}
}
return 0;
}