题目链接:http://poj.org/problem?id=2777
Description
Input
Output
Sample Input
2 2 4 C 1 1 2 P 1 2 C 2 2 2 P 1 2
Sample Output
2 1
Source
题意:
给一个固定长度为L的画板
有两个操作:
C A B C:区间A--B内涂上颜色C。
P A B:查询区间AB内颜色种类数。
PS:此题和HDU:5023是类似的!
附题解:http://blog.csdn.net/u012860063/article/details/39434665
代码例如以下:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define lson l , mid , rt << 1 #define rson mid + 1 , r , rt << 1 | 1 #define LL int const int maxn = 110017; 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] = 1;//初始颜色为1 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 L, T, O; int a, b, c; while(~scanf("%d%d%d",&L,&T,&O)) { build(1, L, 1);//建树 while(O--)//Q为询问次数 { char op[2]; scanf("%s",op); if(op[0] == 'P') { scanf("%d%d",&a,&b); if(a > b) { int t = a; a = b; b = t; } LL tt=query(a, b, 1, L, 1); int ans = 0; while(tt) { if(tt&1) { ans++; } tt>>=1; } printf("%d\n",ans); } else { scanf("%d%d%d",&a,&b,&c); if(a > b) { int t = a; a = b; b = t; } update(a, b, c, 1, L, 1); } } } return 0; }