Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 29895 | Accepted: 8919 |
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
题意:有一块长度为l的木板,这个木板有l个长度为1的小木板组成(每个小木板初始颜色为t1)。现在有t种颜料,o个操作
操作共有2种: C L R V :把木板第L块至R块木板的颜色换成V P L R:求木板L块至R块有多少种不一样的颜色。
思路:经典的线段树题(lazy标记)+按位或运算符('|')求不同颜色的数目
在"改段求段型"模板修改一下,每个结点维护4个值:区间左端点,区间又端点,区间的颜色(lazy),是否都被涂成一样的颜色
关于区间的颜色(lazy):因为t只有小于等于30,所以可以利用二进制的每一位表示一种颜色.
例如:颜色t种颜色:t1...tt
则t1【2^(1-1)】: 0000 0001 t2【2^(2-1)】: 0000 0010 t3:【2^(3-1)】 0000 0100 ....
因为按位或是对应位置有1那么结果就为1,所以如果木板有颜色t1和t2,那么按位或之后就变成 0000 0011
则不同的颜色数目就等于对应数字二进制1的个数.
//#define _CRT_SECURE_NO_DEPRECATE #include<iostream> #include<cmath> #include <algorithm> using namespace std; typedef long long int LL; #define R(k)(k<<1|1) #define L(k)(k<<1) #define INF 0x3f3f3f3f const int MAXN = 100005; const int MAXT = 31; struct Node { int l, r;//区间开始和结束 int col;//用一个32位的int型,每一位对应一种颜色 bool vis;//表示这个区间都被涂上同一种颜色。 }; Node tree[MAXN * 3]; int bit_one(int x)//求整数X转换成二进制后有多少个1 { int m = 0; while (x>0) { x = (x&(x - 1)); m++; } return m; } void build(int s, int e, int k) { if (s == e) { tree[k].l = s; tree[k].r = e; tree[k].col = 1;//注意题目要求每个格子初始颜色为1 tree[k].vis = true; return; } int mid = (s + e) >> 1; tree[k].l = s; tree[k].r = e; tree[k].vis = true; build(s, mid, L(k)); build(mid + 1, e, R(k)); tree[k].col = tree[L(k)].col | tree[R(k)].col; } void pushup(int k) { tree[k].col = tree[L(k)].col | tree[R(k)].col; } void pushdown(int k) { if (tree[k].vis) { tree[L(k)].col = tree[k].col; tree[L(k)].vis = true; tree[R(k)].col = tree[k].col; tree[R(k)].vis = true; tree[k].vis = false; } } void updata(int s, int e, int k, int v) { if (s==tree[k].l&&e==tree[k].r) { tree[k].vis = true; tree[k].col = 1<<(v-1); return; } pushdown(k); int mid = (tree[k].l + tree[k].r) >> 1; if (e <= mid) { updata(s, e, L(k), v); } else if (s > mid) { updata(s, e, R(k), v); } else { updata(s, mid, L(k), v); updata(mid + 1, e, R(k), v); } pushup(k); } int query(int s, int e, int k)//求不用颜色的数目 { if (s == tree[k].l&&e==tree[k].r) { return tree[k].col; } pushdown(k); int mid = (tree[k].l+tree[k].r) >> 1,num; if (e <= mid) { num=query(s, e, L(k)); } else if (s > mid) { num=query(s, e, R(k)); } else { num=query(s, mid, L(k)) | query(mid + 1, e, R(k)); } pushup(k); return num; } int main() { int l, t, o, a, b, c; char ch; scanf("%d %d %d", &l, &t, &o); build(1, l, 1); while (o--) { getchar(); scanf("%c", &ch); if (ch == 'C') { scanf("%d %d %d", &a, &b, &c); updata(a, b, 1, c); } else { scanf("%d %d", &a, &b); printf("%d\n",bit_one(query(a, b, 1))); } } system("pause"); return 0; }
总结:巧妙运用二进制的每一位来表示一种状态,然后利用位运算符来求解答案。
按位或:求解对应二进制中总的(两两不相等)状态数