给出二维平面
$opt1.$ 对点 $(x, y)$ 增减颜色 $c$,
$opt2.$ 询问矩形 $(1, y_1), (x, y_2)$ 内出现过的颜色种数
$x, y <= 1e6, c <= 50$
二维线段树 $hehe$
观察特殊性质每次询问的矩形的左上(下)角都在直线 $x = 1$ 上
假设只有一种颜色
如下平面直角坐标系
这张图貌似并没有什么用
给出黑色点为插入的点
询问绿色矩形内的颜色种数
因为假设只有 $1$ 种颜色
所以只需判断绿色矩形内是否存在插入的点
显然是存在的
Sol
每次插入一个点 $(x, y)$,把 $x$ 当做 $y$ 的权值,线段树维护每个 $y$ 的最小值
即线段树以纵坐标 $y$ 为下标,维护每个数的最小值
相当于单点修改 $y$ 的值为 $min(w_y, x)$
这也就是询问的矩形左上(下)点的特殊性质所在
这样的话
对每个颜色开一颗线段树(动态开点)
每次查询,枚举颜色,线段树查询区间 $(y_1, y_2)$ 内的最小值 $Min$
如果 $Min <= $ 右上(下)点的横坐标则对答案贡献为 $1$
时间复杂度 $O(50nlogn)$
注意:线段树在查询时,如果当前最小值已经 $<=$ 查询的 $x$ 时,不再进行递归
否则会 $TLE$,可能下面的code写都丑
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N = 1e6 + 10; #define gc getchar() inline int read() { int x = 0; char c = gc; while(c < '0' || c > '9') c = gc; while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc; return x; } #undef gc int Root[55], Lson[N * 4], Rson[N * 4], Minx[N * 4]; int js_root; void Clear() { js_root = 0; memset(Root, 0, sizeof Root); memset(Lson, 0, sizeof Lson); memset(Rson, 0, sizeof Rson); memset(Minx, 0x3f, sizeof Minx); } void Poi_G(int l, int r, int &jd, int x, int num) { if(!jd) jd = ++ js_root; Minx[jd] = min(Minx[jd], num); if(l == r) return ; int mid = (l + r) >> 1; if(x <= mid) Poi_G(l, mid, Lson[jd], x, num); else Poi_G(mid + 1, r, Rson[jd], x, num); } int Ans; void Sec_A(int l, int r, int jd, int x, int y, int imp) { if(!jd || Ans <= imp) return ; if(x <= l && r <= y) {Ans = min(Ans, Minx[jd]); return ;} if(l == r) return ; int mid = (l + r) >> 1; if(x <= mid) Sec_A(l, mid, Lson[jd], x, y, imp); if(y > mid) Sec_A(mid + 1, r, Rson[jd], x, y, imp); } int main() { int opt; memset(Minx, 0x3f, sizeof Minx); while(scanf("%d", &opt)) { if(opt == 3) break; else if(opt == 0) Clear(); else if(opt == 1) { int x = read(), y = read(), c = read(); Poi_G(1, N - 10, Root[c], y, x); } else { int x = read(), y_1 = read(), y_2 = read(), Out_Ans(0); if(y_1 > y_2) std:: swap(y_1, y_2); for(int i = 0; i <= 50; i ++) { Ans = Minx[N - 9]; Sec_A(1, N - 10, Root[i], y_1, y_2, x); if(Ans <= x) Out_Ans ++; } printf("%d ", Out_Ans); } } return 0; }