HDU 6621 K-th Closest Distance(主席树+二分)

题意

对于大小为n的正整数数组a,有q次询问,每次询问给出整数数p、k,要求输出离p第k近的数字,强制在线。

思路

主席树维护区间 \([l, r]\) 数字出现次数,二分答案。

Code

	#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxn = 1e5+10;

struct node {
    int l, r, val;
}tr[maxn*21];
int root[maxn], tot, a[maxn], b[maxn];

void build(int l, int r, int &x) {
    x = ++tot;
    if(l==r) return;
    int mid = l+r>>1;
    build(l, mid, tr[x].l); build(mid+1, r, tr[x].r);
}
void update(int l, int r, int x, int &y, int p, int val=1) {
    y = ++tot;
    tr[y] = tr[x];
    tr[y].val += val;
//    cout << l << " " << r << " " <<  tr[y].val << endl;
    if(l==r) return;
    int mid = l+r>>1;
    if(p<=mid) update(l, mid, tr[x].l, tr[y].l, p, val);
    else update(mid+1, r, tr[x].r, tr[y].r, p, val);
}
int query(int l, int r, int x, int y, int L, int R) {
    if(L<=l && r<=R) return tr[y].val-tr[x].val;
    int mid=l+r>>1, ans=0;
    if(L<=mid) ans=query(l, mid, tr[x].l, tr[y].l, L, R);
    if(R>mid) ans+=query(mid+1, r, tr[x].r, tr[y].r, L, R);
    return ans;
}
int T, n, m;
void read(int &x) {
    x=0; char ch, c=getchar();
    while(c<'0' || c>'9') ch=c, c=getchar();
    while(c>='0' && c<='9') x=x*10+c-'0', c=getchar();
    if(ch=='-') x=-x;
}

int main() {
//    freopen("in.txt", "r", stdin);
    scanf("%d", &T);
    while(T--) {
        scanf("%d%d", &n, &m);
        tot=0;
        build(1, maxn, root[0]);
        for (int i=1; i<=n; ++i) {
            scanf("%d", a + i);
            b[i] = a[i];
        }
        sort(b+1, b+1+n);
        int cnt = unique(b+1, b+1+n)-b-1;
        for (int i=1; i<=n; ++i) {
            a[i] = lower_bound(b+1, b+cnt+1, a[i])-b+1;
            update(1, maxn, root[i-1], root[i], a[i]);
        }
        int ans=0;
        for (int L, R, P, K, i=1; i<=m; ++i) {
            scanf("%d%d%d%d", &L, &R, &P, &K);
            L^=ans, R^=ans, P^=ans, K^=ans;
            if(L>R) swap(L, R);
            int l=0, r=1e6+10;
            while(l<r) {
                int mid=l+r>>1;
                int ll = lower_bound(b+1, b+1+cnt, P-mid)-b+1;
                int rr = upper_bound(b+1, b+1+cnt, P+mid)-b;
                int sum = query(1, maxn, root[L-1], root[R], ll, rr);
                if(sum >= K) r=mid;
                else l=mid+1;
            }
            printf("%d\n", l);
            ans = l;
        }
    }
    return 0;
}
posted @ 2019-08-05 20:29  Acerkoo  阅读(161)  评论(0编辑  收藏  举报