线段树。
假设只有一种颜色,因为每次询问有一个$x$一定是$1$,那么我可以想办法找出每一个$y$最小的$x$是多少,如果最小的都不符合,那么一定不符合,因为更新变成了单点更新,询问是区间询问最小值,搞个线段树即可。有$51$种颜色,可以搞$51$个线段树。
#include <bits/stdc++.h> using namespace std; const int maxn = 6000000 + 10; int op; int root[60]; struct Node { int val; int L; int R; }s[maxn]; int num; int add() { num ++; s[num].val = 2000000; s[num].L = -1; s[num].R = -1; return num; } void update(int rt, int pos, int val, int l, int r) { if(l == r) { s[rt].val = min(s[rt].val, val); return ; } int mid = (l + r) / 2; if(pos <= mid) { if(s[rt].L == -1) { s[rt].L = add(); } update(s[rt].L, pos, val, l, mid); } else { if(s[rt].R == -1) { s[rt].R = add(); } update(s[rt].R, pos, val, mid + 1, r); } int left = 2000000; int right = 2000000; if(s[rt].L != -1) { left = s[s[rt].L].val; } if(s[rt].R != -1) { right = s[s[rt].R].val; } s[rt].val = min(left, right); } int query(int rt, int L, int R, int l, int r) { if(L <= l && r <= R) { return s[rt].val; } int mid = (l + r) / 2; int left = 2000000; int right = 2000000; if(L <= mid && s[rt].L != -1) { left = query(s[rt].L, L, R, l, mid); } if(R > mid && s[rt].R != -1) { right = query(s[rt].R, L, R, mid + 1, r); } return min(left, right); } int main() { // freopen("D://in.txt", "r", stdin); while(~scanf("%d", &op)) { if(op == 0) { for(int i = 0; i <= 50; i ++) { root[i] = add(); } } else if(op == 1) { int x, y, c; scanf("%d%d%d", &x, &y, &c); update(root[c], y, x, 1, 1000000); } else if(op == 2) { int x, y1, y2; scanf("%d%d%d", &x, &y1, &y2); int ans = 0; for(int i = 0; i <= 50; i ++) { if(query(root[i], y1, y2, 1, 1000000) <= x) { ans ++; } } printf("%d ", ans); } else { break; } } return 0; }