题目链接:K小数查询
题意:给你一个长度为$n$序列$A$,有$m$个操作,操作分为两种:
- 输入$x,y,c$,表示对$iin[x,y] $,令$A_{i}=min(A_{i},c)$
- 输入$x,y,k$,表示询问区间$[x,y]$中的第$k$小数
思路:数据范围不是很大,可以分块来做,记录每个块已经更新过的最小值$imin[]$,询问时二分答案,然后求出$[x,y]$区间中小于等于$mid$的数的个数$cnt$,通过判断$cnt$与$k$的大小来改变$l,r$即可
#include <iostream> #include <algorithm> #include <cstdio> #include <vector> #include <cmath> using namespace std; const int N = 100010; const int INF = 0x3f3f3f3f; int block, belong[N], num, l[N], r[N], imin[N]; int n, m, a[N]; vector<int> v[N]; void build() { block = sqrt(n); num = n / block; if (n % block) num++; for (int i = 1; i <= num; i++) l[i] = (i - 1) * block + 1, r[i] = i * block; r[num] = n; for (int i = 1; i <= n; i++) belong[i] = (i - 1) / block + 1; for (int i = 1; i <= num; i++) { imin[i] = INF; for (int j = l[i]; j <= r[i]; j++) v[i].push_back(a[j]); sort(v[i].begin(), v[i].end()); } } void reset(int x) { v[x].clear(); for (int i = l[x]; i <= r[x]; i++) { a[i] = min(a[i], imin[x]); v[x].push_back(a[i]); } sort(v[x].begin(), v[x].end()); } void update(int x, int y, int c) { int bl = belong[x], br = belong[y]; if (bl == br) { for (int i = x; i <= y; i++) a[i] = min(a[i], c); reset(bl); return; } for (int i = x; i <= r[bl]; i++) a[i] = min(a[i], c); reset(bl); for (int i = l[br]; i <= y; i++) a[i] = min(a[i], c); reset(br); for (int i = bl + 1; i < br; i++) imin[i] = min(imin[i], c); } int query(int x, int y, int c) { int bl = belong[x], br = belong[y], cnt = 0; if (bl == br) { for (int i = x; i <= y; i++) if (a[i] <= c || imin[bl] <= c) cnt++; return cnt; } for (int i = x; i <= r[bl]; i++) if (a[i] <= c || imin[bl] <= c) cnt++; for (int i = l[br]; i <= y; i++) if (a[i] <= c || imin[br] <= c) cnt++; for (int i = bl + 1; i < br; i++) if (imin[i] <= c) cnt = cnt + r[i] - l[i] + 1; else cnt = cnt + upper_bound(v[i].begin(), v[i].end(), c) - v[i].begin(); return cnt; } int ask(int x, int y, int k) { int l = -1000000000, r = 1000000000; while (l < r) { int mid = (l + r) / 2; if (query(x, y, mid) >= k) r = mid; else l = mid + 1; } return l; } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); build(); for (int i = 1; i <= m; i++) { int kd, x, y, c; scanf("%d%d%d%d", &kd, &x, &y, &c); if (1 == kd) update(x, y, c); else printf("%d ", ask(x, y, c)); } return 0; }