题意 : 给出 n 个染色操作,问你到最后区间上能看见的各个颜色所拥有的区间块有多少个
分析 : 使用线段树成段更新然后再暴力查询总区间的颜色信息即可,这里需要注意的是给区间染色,而不是给点染色,所以对于区间(L, R)我们只要让左端点+1即可按照正常的线段树操作来做。
#include<bits/stdc++.h> #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 using namespace std; const int maxn = 8000 + 5; const int INF = 0x3f3f3f3f; struct Query{ int L, R, val; }; int col[maxn<<2], cnt[maxn], Rmax, ColorMax; Query Q[maxn]; inline void PutDown(int rt) { if(col[rt] >= 0){ col[rt<<1] = col[rt<<1|1] = col[rt]; col[rt] = -1; } } inline void update(int L, int R, int val, int l, int r, int rt) { if(L <= l && r <= R){ col[rt] = val; return ; } PutDown(rt); int m = (l + r) / 2; if(L <= m) update(L, R, val, lson); if(R > m) update(L, R, val, rson); } int query(int pos, int l, int r, int rt) { if(l == r) return col[rt]; PutDown(rt); int m = (l + r) / 2; int ret; if(pos <= m) ret = query(pos, lson); if(pos > m) ret = query(pos, rson); return ret; } int main(void) { int paint; while(~scanf("%d", &paint)){ Rmax = ColorMax = -INF; for(int i=1; i<=paint; i++){ scanf("%d %d %d", &Q[i].L, &Q[i].R, &Q[i].val); Q[i].L++; Rmax = max(Rmax, Q[i].R);///记录区间右端可以多大 ColorMax = max(ColorMax, Q[i].val);///记录颜色的最大值 } memset(col, -1, sizeof(col)); for(int i=1; i<=paint; i++){ if(Q[i].L-1 < Q[i].R)///说明给出的是一个点,没有覆盖掉哪一段,不用更新 update(Q[i].L, Q[i].R, Q[i].val, 1, Rmax, 1); } memset(cnt, 0, sizeof(cnt)); int last = -1; for(int i=1; i<=Rmax; i++){///查询区间内每个点的信息,用cnt[]数组来记录拥有的这些颜色占的段数 int color = query(i, 1, Rmax, 1); if(color == -1) {last = -1; continue;}///注意如果没有被染色,last要赋值成-1,不能直接continue if(color != last){ cnt[color]++; } last = color; } for(int i=0; i<=ColorMax; i++){ if(cnt[i]>0){ printf("%d %d ", i, cnt[i]); } } puts(""); } return 0; }
瞎 : query操作的时候由于有lazy tag所以需要PutDown,此题虽然不难但是如果独立写一个线段树并且AC估计能够发现自身的一些问题,注意实现细节....