题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5023
题意:
P :A到B区间图上第C种颜色;
Q:A到B所有点存在的颜色种类;
PS: 按照队友的思路代码讲解来得,给跪了;
思路:
就是利用优美的位运算的性质,初始为1,当有某种颜色时就<<代表此种颜色的数字,
最后在每次输出的时候再从1到30种颜色中逐一>>并&1就可以检验是否含有这种颜色!
PS:
此题和POJ:2777类似;
附题解:http://blog.csdn.net/u012860063/article/details/40433725
代码如下:
#include
#include
#include
using namespace std;
#define lson l , mid , rt << 1
#define rson mid + 1 , r , rt << 1 | 1
#define LL int
const int maxn = 1100017;
LL add[maxn<<2];
LL sum[maxn<<2];
void PushUp(int rt)
{
//把当前结点的信息更新到父结点
sum[rt] = sum[rt<<1] | sum[rt<<1|1];//总共的颜色
}
void PushDown(int rt,int m)
{
if(add[rt])
{
add[rt<<1] = add[rt];
add[rt<<1|1] = add[rt];
sum[rt<<1] = add[rt] ;
sum[rt<<1|1] = add[rt] ;
add[rt] = 0;//将标记向儿子节点移动后,父节点的延迟标记去掉
//传递后,当前节点标记域清空
}
}
void build(int l,int r,int rt)
{
add[rt] = 0;//初始化为所有结点未被标记
if (l == r)
{
sum[rt]=2;//初始颜色为2
return ;
}
int mid = (l + r) >> 1;
build(lson);
build(rson);
PushUp(rt);
}
void update(int L,int R,int c,int l,int r,int rt)
{
if (L <= l && r <= R)
{
add[rt] =1<<(c-1);//位运算左移表示有某种颜色
sum[rt] =1<<(c-1);
return ;
}
PushDown(rt , r - l + 1);//----延迟标志域向下传递
int mid = (l + r) >> 1;
if (L <= mid)
update(L , R , c , lson);//更新左儿子
if (mid < R)
update(L , R , c , rson);//更新右儿子
PushUp(rt);
}
LL query(int L,int R,int l,int r,int rt)
{
if (L <= l && r <= R)
{
return sum[rt];
}
//要取rt子节点的值时,也要先把rt的延迟标记向下移动
PushDown(rt , r - l + 1);
int mid = (l + r) >> 1;
LL ret = 0;
if (L <= mid)
ret |= query(L , R , lson);
if (mid < R)
ret |= query(L , R , rson);
return ret;
}
int main()
{
int N , Q;
int a , b , c;
while(scanf("%d%d",&N,&Q))
{
if(N==0 && Q==0)
break;
build(1 , N , 1);//建树
while(Q--)//Q为询问次数
{
char op[2];
scanf("%s",op);
if(op[0] == 'Q')//Q为询问次数
{
scanf("%d%d",&a,&b);
LL tt=query(a , b , 1 , N , 1);
LL flag = 0;
for(int i=1; i<=30; i++)
{
if(tt>>(i-1)&1 && flag==0)
{
printf("%d",i);
flag = 1;
}
else if(tt>>(i-1)&1)
printf(" %d",i);
}
printf("\n");
}
else
{
scanf("%d%d%d",&a,&b,&c);
update(a , b , c , 1 , N , 1);
}
}
}
return 0;
}