简单题意:给定一个长度为n的序列,有m次查询,要求算出在[L, R]的区间内,小于k值的个数有几个。
分析:数据在1e5左右,很明显想到的是主席树的结构,维护区间的信息。因为通过主席树我们可以直接查出第k大值,而且根据主席树是权值线段树的性质,符合单调的性质,所以可以二分第几大的数去逼近k值,最后算出位置就说明前面有多少数字比他小。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <cmath>
#include <bitset>
#include <map>
#include <set>
//#define ACM_LOCAL
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e5 + 5, M = 5e5 + 5, INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
int a[N], rt[N];
int n, m;
struct Hash {
int b[N], tot;
void init() {tot = 0;}
void insert(int x) {b[++tot] = x;}
void build() {
sort(b+1, b+1+tot);
tot = unique(b+1, b+tot+1) - (b+1);
}
int pos(int x) {return lower_bound(b+1, b+tot+1, x) - b;}
}ha;
struct {
int t[N << 5], lc[N << 5], rc[N << 5];
int NodeNum = 0;
ll sum[N << 5];
int build(int l, int r) {
int num = ++NodeNum;
if (l != r) {
int mid = (l + r) >> 1;
lc[num] = build(l, mid);
rc[num] = build(mid + 1, r);
}
return num;
}
int update(int pre, int l, int r, int x) {
int num = ++NodeNum;
lc[num] = lc[pre], rc[num] = rc[pre], t[num] = t[pre] + 1;
if (l != r) {
int mid = (l + r) >> 1;
if (x <= mid) lc[num] = update(lc[pre], l, mid, x);
else rc[num] = update(rc[pre], mid + 1, r, x);
}
return num;
}
int Qry_Kth_Num(int u, int v, int l, int r, int k) {
if (l == r) return ha.b[l];
int mid = (l + r) >> 1, num = t[lc[v]] - t[lc[u]];
if (num >= k) return Qry_Kth_Num(lc[u], lc[v], l, mid, k);
else return Qry_Kth_Num(rc[u], rc[v], mid + 1, r, k-num);
}
ll Qry_Kth_Sum(int u, int v, int l, int r, int k) {//k大数之和
if (l == r) return 1ll*ha.b[l] * k;
int mid = (l + r) >> 1, num = t[rc[v]] - t[rc[u]];
if (num >= k) return Qry_Kth_Sum(rc[u], rc[v], mid+1, r, k);
else return sum[rc[v]] - sum[rc[u]] + Qry_Kth_Sum(lc[u], lc[v], l, mid, k-num);
}
int Binary_Search(int left, int right, int val) {
int l = 1, r = right - left + 1;
while (l <= r) {
int mid = l + r >> 1;
int num = Qry_Kth_Num(rt[left - 1], rt[right], 1, ha.tot, mid);
if (num > val) r = mid - 1;
else l = mid + 1;
}
return r;
}
}hjt;
void solve() {
int T, c; scanf("%d", &T);
while (T--) {
scanf("%d %d", &n, &m);
ha.init(); hjt.NodeNum = 0;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
ha.insert(a[i]);
}
ha.build();
rt[0] = hjt.build(1, ha.tot);
for (int i = 1; i <= n; i++) {
rt[i] = hjt.update(rt[i-1], 1, ha.tot, ha.pos(a[i]));
}
printf("Case %d:\n", ++c);
while (m--) {
int l, r, val;
scanf("%d %d %d", &l, &r, &val);
l++, r++;
printf("%d\n", hjt.Binary_Search(l, r, val));
}
}
}
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#ifdef ACM_LOCAL
freopen("input", "r", stdin);
freopen("output", "w", stdout);
#endif
solve();
return 0;
}
当然也可以考虑分块,用upper_bound来查询有多少数子比他小。时间复杂度大约是n n \sqrt{n} n,控制一下常数也可以过。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <cmath>
#include <bitset>
#include <map>
#include <set>
#define ACM_LOCAL
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e5 + 5, M = 5e5 + 5, INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
int a[N], belong[N], tag[N];
int n, m, block, num;
vector<int> ve[N];
int query(int x, int y, int val) {
int ans = 0, pos1 = belong[x], pos2 = belong[y];
for (int i = x; i <= min(y, block * pos1); i++)
if (a[i] <= val) ans++;
if (pos1 != pos2)
for (int i = (pos2-1)*block+1; i <= y; i++)
if (a[i] <= val) ans++;
for (int i = pos1+1; i <= pos2-1; i++) {
ans += upper_bound(ve[i].begin(), ve[i].end(), val) - ve[i].begin();
}
return ans;
}
void solve() {
int T, c = 0; scanf("%d", &T);
while (T--) {
scanf("%d %d", &n, &m);
block = sqrt(n);
num = n / block + (n % block);
for (int i = 1; i <= num; i++) ve[i].clear();
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
belong[i] = (i - 1) / block + 1;
ve[belong[i]].push_back(a[i]);
}
for (int i = 1; i <= num; i++)
sort(ve[i].begin(), ve[i].end());
printf("Case %d:\n", ++c);
for (int i = 1; i <= m; i++) {
int l, r, val;
scanf("%d %d %d", &l, &r, &val);
l++, r++;
printf("%d\n", query(l, r, val));
}
}
}
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#ifdef ACM_LOCAL
freopen("input", "r", stdin);
freopen("output", "w", stdout);
#endif
solve();
return 0;
}