zoj 1610 Count the Colors
这里主要复习下线段树点的意义。这里的染色区域L,和R,是指将这样一个线段[L,R]染色,而非点染色。那么,我们可以人为地改变线段树中每个点的意义:从树原本的一个叶子表示一个点,改成表示一条长度为1的线段。比如[1,2]这个线段,用2来表示即可,那么染色[u,v],相当于染色[u+1,v]。问题来了:为什么不用1来表示[1,2]呢?
因为:用末端来表示线段,相当于用(a,b]表示这条线段,即后端准确,前面的线段即使和a重合,也不影响(a,b]。
假设是用首端来表示线段,相当于用[a,b)表示,即前端准确,假设前面的线段和a重合,比如染色b->c为A色,再染a->b为B色,那么b被B占领,实际上的b->(b+1)这段颜色被消灭了(这不应该)。
#include <stdio.h> #include <memory.h> #include <algorithm> #include <iostream> using namespace std; #define ll long long #define FOR(i,a,b) for(int i=(a);i<=(b);++i) #define DOR(i,a,b) for(int i=(a);i>=(b);--i) const int maxN=8e3+5,inf=0x3f3f3f3f; int N, M, K, T; // g[rt]: -1:不必更新 int cr[maxN<<4], g[maxN<<4]; int ans[maxN]; #define lson l,m,rt*2 #define rson m+1,r,rt*2+1 void push_down(int rt) { if (g[rt] == -1) return; int lch = rt * 2, rch = lch + 1; g[lch] = g[rch] = g[rt]; cr[lch] = cr[rch] = g[rt]; g[rt] = -1; } void update(int L, int R, int C, int l, int r, int rt) { if (L <= l && r <= R) { g[rt] = C; cr[rt] = C; return; } push_down(rt); int m = (l + r) / 2; if (L <= m) update(L, R, C, lson); if (R > m) update(L, R, C, rson); } int pre, first; void query(int l, int r, int rt) { if (l == r) { if (first) { first = 0; } if (cr[rt] != pre && cr[rt] != -1) ans[cr[rt]]++; pre = cr[rt]; return; } push_down(rt); int m = (l + r) / 2; query(lson); query(rson); } int main () { #ifndef ONLINE_JUDGE freopen("data.in", "r", stdin); #endif N = 8000 + 1; // N = 3; while (~scanf("%d", &M)) { // build tree memset(g, -1, sizeof g); memset(cr, -1, sizeof cr); memset(ans, 0, sizeof ans); int u, v, w; FOR(i, 1, M) { scanf("%d%d%d", &u, &v, &w); update(u + 1, v, w, 0, N, 1); } first = 1; query(0, N, 1); FOR(i, 0, N) if (ans[i]) printf("%d %d\n", i, ans[i]); puts(""); } return 0; }