There is a very long board with length L centimeter, L is a positive integer, so we can evenly divide the board into L segments, and they are labeled by 1, 2, … L from left to right, each is 1 centimeter long. Now we have to color the board - one segment with only one color. We can do following two operations on the board:
- “C A B C” Color the board from segment A to segment B with color C.
- “P A B” Output the number of different colors painted between segment A and segment B (including).
In our daily life, we have very few words to describe a color (red, green, blue, yellow…), so you may assume that the total number of different colors T is very small. To make it simple, we express the names of colors as color 1, color 2, … color T. At the beginning, the board was painted in color 1. Now the rest of problem is left to your.
Input
First line of input contains L (1 <= L <= 100000), T (1 <= T <= 30) and O (1 <= O <= 100000). Here O denotes the number of operations. Following O lines, each contains “C A B C” or “P A B” (here A, B, C are integers, and A may be larger than B) as an operation defined previously.
Output
Ouput results of the output operation in order, each line contains a number.
Sample Input
2 2 4
C 1 1 2
P 1 2
C 2 2 2
P 1 2
Sample Output
2
1
区间染色问题,这里的颜色数量非常少,只有30种,因此可以用线段树+状压来维护
用一个数的二进制每一位来表示有没有这种颜色,利用“或”预算就能轻易的合并状态,最后用“与”运算按位取出。
30种颜色,需要一个2^30的数,刚刚好能用int存下。
// #include<bits/stdc++.h>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 100005;
int sum[maxn << 2], lazy[maxn << 2];
//这是用来debug的,输出二进制
void print_bin(int n) {
int l = sizeof(n) * 8; //总位数。
int i;
if(i == 0) {
printf("0");
return;
}
for(i = l - 1; i >= 0; i --) { //略去高位0.
if(n & (1 << i)) break;
}
for(; i >= 0; i --)
printf("%d", (n & (1 << i)) != 0);
}
void pushUp(int i) {
// 或运算合并状态
sum[i] = sum[i << 1] | sum[i << 1 | 1];
}
void pushDown(int i) {
if(!lazy[i]) {
return;
}
sum[i << 1] = sum[i];
sum[i << 1 | 1] = sum[i];
lazy[i << 1] = 1;
lazy[i << 1 | 1] = 1;
lazy[i] = 0;
}
void build(int i, int l, int r) {
sum[i] = 1;
if(l == r) {
return;
}
int mid = (l + r) / 2;
build(i << 1, l, mid);
build(i << 1 | 1, mid + 1, r);
}
void update(int i, int L, int R, int l, int r, int cor) {
if(l >= L && r <= R) {
sum[i] = 1 << (cor - 1);
lazy[i] = 1;
return;
}
pushDown(i);
int mid = (l + r) / 2;
if(L <= mid) {
update(i << 1, L, R, l, mid, cor);
}
if(R > mid) {
update(i << 1 | 1, L, R, mid + 1, r, cor);
}
pushUp(i);
}
int query(int i, int L, int R, int l, int r) {
if(l >= L && r <= R) {
return sum[i];
}
pushDown(i);
int ans = 0;
int mid = (l + r) / 2;
if(L <= mid) {
ans |= query(i << 1, L, R, l, mid);
}
if(R > mid) {
ans |= query(i << 1 | 1, L, R, mid + 1, r);
}
return ans;
}
int main() {
int n, t, m;
scanf("%d%d%d", &n, &t, &m);
build(1, 1, n);
while(m--) {
char op;
int l, r;
scanf("\n%c%d%d", &op, &l, &r);
// 这有一个坑,你懂的
if(l > r){
swap(l,r);
}
if(op == 'C') {
int cor;
scanf("%d", &cor);
update(1, l, r, 1, n, cor);
} else {
int ans = query(1, l, r, 1, n);
int cnt = 0;
for(int i = 0; i < t ; i++) {
int get = ans & (1 << i);
if(get) {
cnt++;
}
}
printf("%d\n", cnt);
// printf("%d\n",ans);
// print_bin(ans);
// printf("\n");
}
}
return 0;
}
第一次见到这题的时候直接懵逼,第二次见的时候直接秒了….嗯,真舒服,果然有些题做不出是因为火候不够,没必要硬上,等水平到了,回头一看简单得飞起。