题目链接:http://poj.org/problem?id=2777
题目大意:
给定n个板子,和t种颜色,o次操作,每次有两种操作:
C a b x操作:把[a,b]区间内的版子全都涂成x色
P a b操作 :查询[a,b]内有多少种颜色
思路:
首先看n的范围和t的范围
t只有30,比较小,可以用二进制存储每一种颜色,比如010是一种,001又是一种,011就是两种了
也可以开一个k[30],开存储每一种颜色
然后就是着色,就用线段树处理区间问题,注意lazy标签的下传和变量l,r,L,R之间的区分
基本上就是一个板子题
代码:
如果想看骚操作看这里:http://www.oier.cc/poj2777countcolor/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=100000+5;
int n,t,o;
int tree[maxn<<2];
int lazy[maxn<<2];
void pushUp(int rt,int l,int r)
{
tree[rt]=tree[rt<<1] | tree[rt<<1|1];//异或处理==颜色求和
}
void pushDown(int rt,int l,int r)
{
if(lazy[rt])
{
tree[rt<<1]=tree[rt<<1|1]=tree[rt];
lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
lazy[rt]=0;
}
}
void build(int rt,int l,int r)
{
tree[rt]=1;
if(l==r)
{
return;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
}
int query(int rt,int l,int r,int x,int y)
{
if(x<=l && y>=r)
{
return tree[rt];
}
pushDown(rt,l,r);
int m1,m2,mid;
m1=m2=0;
mid=(l+r)>>1;
if(x<=mid) m1=query(rt<<1,l,mid,x,y);
if(y>mid) m2=query(rt<<1|1,mid+1,r,x,y);
return m1|m2;
}
void update(int rt,int l, int r,int x,int y,int color)
{
if(l>=x && r<=y)//到达节点,并且根节点为x
{
tree[rt] = 1<< (color-1);
lazy[rt] = 1;
return;
}
pushDown(rt,l,r);
int mid=(l+r)>>1;
if(x<=mid)
update(rt<<1,l,mid,x,y,color);//往左边查询
if(y>mid)
update(rt<<1|1,mid+1,r,x,y,color);//往右边查询
pushUp(rt,l,r);//更新自己
}
int main()
{
scanf("%d %d %d",&n,&t,&o);
build(1,1,n);
// update(1,1,n,1,n,1);
char c;
int l,r,color;
while(o--)
{
getchar();
scanf("%c",&c);
if(c=='C')
{
scanf("%d%d%d",&l,&r,&color);
update(1,1,n,l,r,color);
}
else
{
scanf("%d%d",&l,&r);
if(l>r)swap(l,r);
int ans=query(1,1,n,l,r);
int sum=0;
while(ans>0)
{
if(ans & 1) sum++;
ans>>=1;
}
printf("%d\n",sum);
}
}
return 0;
}