题意:
刚刚开始的时候所有的片段上的颜色都是2。
在片段上着色,有两种操作,如下:
第一种:P a b c 把 a 片段至 b 片段的颜色都变为 c 。
第二种:Q a b 询问 a 片段至 b 片段有哪些颜色,把这些颜色按从小到大的编号输入,不要有重复。
解析:
很简单的线段树区间合并问题。
对于1操作,可以利用线段树进行区间覆盖。
对于2操作,每查询到一个有颜色的区间就丢进set中,最后把set中的元素一起输出。
my code
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#define ls (o<<1)
#define rs (o<<1|1)
#define lson ls, L, M
#define rson rs, M+1, R
#define MID (L + R) >> 1
#define SEG(L, R) 1, L, R
using namespace std;
const int N = (int)1e6 + 10;
int n, m;
int cov[N<<2];
set<int> st;
set<int>::iterator it;
inline void pushDown(int o) {
if(cov[o] != -1) {
cov[ls] = cov[rs] = cov[o];
cov[o] = -1;
}
}
inline void pushUp(int o) {
if(cov[ls] == cov[rs]) {
cov[o] = cov[ls];
}else cov[o] = -1;
}
void build(int o, int L, int R) {
cov[o] = -1;
if(L == R) {
cov[o] = 2;
return ;
}
int M = MID;
build(lson);
build(rson);
pushUp(o);
}
void modify(int o, int L, int R, int ql, int qr, int val) {
if(ql <= L && R <= qr) {
cov[o] = val;
return ;
}
int M = MID;
pushDown(o);
if(ql <= M) modify(lson, ql, qr, val);
if(qr > M) modify(rson, ql, qr, val);
pushUp(o);
}
void query(int o, int L, int R, int ql, int qr) {
if(cov[o] != -1 && ql <= L && R <= qr) {
st.insert(cov[o]);
return ;
}
int M = MID;
pushDown(o);
if(ql <= M) query(lson, ql, qr);
if(qr > M) query(rson, ql, qr);
pushUp(o);
}
void output() {
it = st.begin();
printf("%d", *it); it++;
for(; it != st.end(); it++) {
printf(" %d", *it);
}
puts("");
}
int main() {
char op[5];
int ql, qr, val;
while(~scanf("%d%d", &n, &m) && (n || m)) {
build(1, 1, n);
while(m--) {
scanf("%s", op);
if(op[0] == 'P') {
scanf("%d%d%d", &ql, &qr, &val);
modify(SEG(1, n), ql, qr, val);
}else {
scanf("%d%d", &ql, &qr);
st.clear();
query(SEG(1, n), ql, qr);
output();
}
}
}
return 0;
}