K-th Closest Distance

K-th Closest Distance HDU - 6621

题意:

给一个长度为n的数组,你有m次询问 每次询问有 \(l, r, p, k\)表示 区间 \(l 到 r\)每个数距离 p的距离第k小是多少?

题解:

A:这题我想到了用二分。但是还是不会写。

B:这题直接二分答案, 假设当前二分的值为 mid 那么就找 \([p - mid - 1, p + mid]\)中在 区间 $l 到 r $中的个数,

要是个数大于等于 k 表示当前答案可以, 继续扩大分。

A: 我想到了但是我不会找在这范围内的个数。

B:这个方法有很多, 你可用vector建立线段树进行二分查找, 或者直接用主席树,查 小于等于 \(p - mid - 1\)在区间 \(l到r\)中的个数, 在查 小于或等于 \(p + mid\) 在 $ l 到 r$区间的个数, 然后做差就是 这个范围内的个数了。

A:哦哦我懂了。

B:这题要注意,强制在线, 记得所有询问的都要强制在线,要不然会一直 段错误。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 7;
int a[N], n, q, t, top = 1, rt[N];
#define m (l + r) / 2

struct hjt {
    int l, r, sum;
}tree[24 * N];

vector<int> g;

int get_id(int x) {
    return lower_bound(g.begin(), g.end(), x) - g.begin() + 1;
}


void update(int pos, int last, int &now, int l, int r) {
    now = top++;
    tree[now] = tree[last];
    tree[now].sum++;
    if (l == r) return;
    if (pos <= m) update(pos, tree[last].l, tree[now].l, l, m);
    else update(pos, tree[last].r, tree[now].r, m + 1, r);
}

int query(int v, int last, int now, int l, int r) {
    if(v == 0) return 0;
    if (l == r) {
        return tree[now].sum - tree[last].sum;
    }
    int ans = 0;
    int sum = tree[tree[now].l].sum - tree[tree[last].l].sum;
    if (v <= m) {
        ans += query(v, tree[last].l, tree[now].l, l, m);
    } else {
        ans += sum;
        ans += query(v, tree[last].r, tree[now].r, m + 1, r);
    }
    return ans;
}

int main() {
    scanf("%d", &t);
    while (t--) {
        top = 1;
        g.clear();
        scanf("%d %d", &n, &q);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            g.push_back(a[i]);
        }
        
        sort(g.begin(), g.end());
        g.push_back(g[0] - 1);
        sort(g.begin(), g.end());
        g.push_back(100000000);
        g.erase(unique(g.begin(), g.end()), g.end());
        
        for (int i = 1; i <= n; i++) {
            int pos  = get_id(a[i]);
            update(pos, rt[i - 1], rt[i], 1, (int)g.size());
        }  
        int last = 0;
        while (q--) {
            int ql, qr, p, k;
            scanf("%d %d %d %d", &ql, &qr, &p, &k);
            int l = 0, r = 1000000, ans;
          
            ql = last ^ ql;
            qr = last ^ qr;
            p = last ^ p;
            k = last ^ k;

            while (l <= r) {
                int down = p - m;
                int up = p + m;
                down = get_id(down);
                down--;
                up = upper_bound(g.begin(), g.end(), up) - g.begin() + 1;
                up--;
                cout <<"down " << down << " " << up << endl;
                if(down > up) down = up;
                int cntl = query(down, rt[ql - 1], rt[qr], 1, (int)g.size());
                int cntr = query(up, rt[ql - 1], rt[qr], 1, (int)g.size());
                int cnt = cntr - cntl ;
                cout << "m " << m << " cnt " << cnt << endl;
                if (cnt >= k) {
                    ans = m;
                    r = m - 1;
                } else {
                    l = m + 1;
                }
            }
            printf("%d\n", ans);
            last = ans;
        }
        for (int i = 0; i <= top; i++) {
            tree[i].l = tree[i].r = tree[i].sum = 0;
        }
        for (int i = 0; i <= n; i++) {
            rt[i] = 0;
        }
    }
}
posted @ 2020-07-11 13:56  ccsu_zhaobo  阅读(73)  评论(0)    收藏  举报