08 K-th Closest Distance
题意:询问区间l,r中与数p的距离为第k大的数 求这个距离
题解:很裸的主席树 二分答案 然后可以用主席数判断在这个区间内 一段值域内出现的数
之前没写过主席树求 统计小于区间某个数的个数 自作主张写的二分区间k小 loglog tle死
看了汪聚聚的代码 才明白主席树功能的强大 以后会了
#include <bits/stdc++.h> using namespace std; const int MAXN = 1e5 + 5; int n, m, cnt, len; int a[MAXN]; int b[MAXN]; int sum[MAXN << 5]; int ls[MAXN << 5]; int rs[MAXN << 5]; int t[MAXN]; int build(int l, int r) { int rt = ++cnt; int m = l + r >> 1; sum[rt] = 0; if(l < r) { ls[rt] = build(l, m); rs[rt] = build(m + 1, r); } return rt; } int add(int o, int l, int r, int k) { int rt = ++cnt; int m = l + r >> 1; ls[rt] = ls[o]; rs[rt] = rs[o]; sum[rt] = sum[o] + 1; if(l < r) { if(k <= m) ls[rt] = add(ls[o], l, m, k); else rs[rt] = add(rs[o], m + 1, r, k); } return rt; } int query(int x, int y, int l, int r, int ql, int qr) { if(ql <= l && qr >= r) return sum[y] - sum[x]; int res = 0; int m = l + r >> 1; if(ql <= m) res += query(ls[x], ls[y], l, m, ql, qr); if(qr > m) res += query(rs[x], rs[y], m + 1, r, ql, qr); return res; } bool check(int ql, int qr, int x, int y, int k) { int t1 = lower_bound(b + 1, b + 1 + len, ql) - b; int t2 = lower_bound(b + 1, b + 1 + len, qr + 1) - b - 1; if(t1 > t2 || t2 > len || t1 > len) return 0; int tmp = query(t[x - 1], t[y], 1, len, t1, t2); if(tmp >= k) return 1; else return 0; } int main() { int T; scanf("%d", &T); while(T--) { scanf("%d%d", &n, &m); cnt = 0; for(int i = 1; i <= n; i++) scanf("%d", &a[i]), b[i] = a[i]; sort(b + 1, b + 1 + n); len = unique(b + 1, b + 1 + n) - b - 1; t[0] = build(1, len); for(int i = 1; i <= n; i++) { int tt = lower_bound(b + 1, b + 1 + len, a[i]) - b; t[i] = add(t[i - 1], 1, len, tt); } int x = 0; for(int i = 1; i <= m; i++) { int l, r, p, k; scanf("%d%d%d%d", &l, &r, &p, &k); l ^= x, r ^= x, p ^= x, k ^= x; int l1 = 0, r1 = 1e6; int mid = l1 + r1 >> 1; while(l1 + 1 < r1) { mid = l1 + r1 >> 1; if(check(p - mid, p + mid, l, r, k)) r1 = mid; else l1 = mid; } if(check(p - l1, p + l1, l, r, k)) x = l1; else x = r1; printf("%d ", x); } } return 0; }