题目来源:http://poj.org/problem?id=2777
题目意思很好懂 就是求解一段区间不同的数字的个数
由于数字的种类小于30
所以可以用位运算来代表不同的种类 纠结了好久开始一直TLE后来才改的位运算
然后用到的就是区间的覆盖问题了
值得注意的就是开始的颜色为 1 A可能大于B
#include <iostream>
#include <cstdio>
#include <cstring>
#define MAX 100010
using namespace std;
typedef struct
{
int l;
int r;
int cov;
int cc;
} Tree;
Tree tree[MAX*5];
int L,T,O;
void update(int i)
{
if(tree[i].cov!=-1)
{
tree[i].cc=tree[i].cov; //直接覆盖
tree[i<<1].cov=tree[i].cov;
tree[(i<<1)+1].cov=tree[i].cov;
tree[i].cov=-1;
}
}
int build(int i,int l,int r)
{
int mid;
tree[i].l=l;
tree[i].r=r;
tree[i].cov=-1;
tree[i].cc=1;
if(l==r)
return 0;
mid=(l+r)>>1;
build(i<<1,l,mid);
build((i<<1)+1,mid+1,r);
}
int cover(int i,int x,int y,int now)
{
int mid;
update(i);
if((x<=tree[i].l)&&(y>=tree[i].r))
{
tree[i].cov=now;
return 0;
}
mid=(tree[i].l+tree[i].r)>>1;
if(x<=mid) cover(i<<1,x,y,now);
if(y>mid) cover((i<<1)+1,x,y,now);
update(i<<1);
update((i<<1)+1);
tree[i].cc=(tree[i<<1].cc|tree[(i<<1)+1].cc);
}
int cal(int i,int x,int y)
{
int mid;
int ans=0;
update(i);
if ((x<=tree[i].l)&&(y>=tree[i].r))
return tree[i].cc;
mid=(tree[i].l+tree[i].r)>>1;
if (x<=mid) ans=(ans|cal(i<<1,x,y)); //位运算 或
if (y>mid) ans=(ans|cal((i<<1)+1,x,y));
update(i<<1);
update((i<<1)+1);
tree[i].cc=(tree[i<<1].cc | tree[(i<<1)+1].cc); // 位运算 或
return ans;
}
int MUN(int i)
{
int count = 0;
while(i)
{
if(i & 1) count ++;
i = i >> 1;
}
return count;
}
int main()
{
scanf("%d%d%d",&L,&T,&O);
build(1,1,L);
char ch;
for(int i=1; i<=O; i++)
{
getchar();
ch=getchar();
if(ch=='C')
{
int x,y,c;
scanf("%d%d%d",&x,&y,&c);
if(x>y)
{
x^=y^=x^=y;
}
int v=(1<<(c-1)); //位运算 第几种颜色就是把1 左移几位
cover(1,x,y,v);
}
else
{
int x,y;
scanf("%d%d",&x,&y);
if(x>y)
{
x^=y^=x^=y;
}
int ans=cal(1,x,y);
printf("%d\n",MUN(ans));
}
}
}