HDU 6621 K-th Closest Distance

杭电多校第4场08题。

主席树+二分

看到题目应该是用主席树。当时看到k最大只有169,就想着先找到p在区间内的排名,然后暴力查找,写了好久,代码有点难调,交上去就是RE,应该是WA了,导致异或那步错了,进而导致RE。

题解是主席树加二分,二分答案mid,然后用主席树查询区间l-r内,值域在[p-mid,p+mid]内的点的个数,如果个数大于k个,说明我们的mid选大了,然后就要减小mid,否则增大mid,二分即可。


#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
const int M = 1e6 + 10;
//const int mx = 1e6;
struct tree{
    int cnt, lc, rc;
}T[(M << 6)];
int root[N], a[N], b[N];
int n, m, q, tot;
void build(int &rt, int l, int r)//建立一颗空树
{
    rt = ++tot;
    T[rt].cnt = 0;
    T[rt].lc = T[rt].rc = 0;
    if (l == r) return;
    int mid = (l + r) >> 1;
    build(T[rt].lc, l, mid);
    build(T[rt].rc, mid + 1, r);
}
void insert(int l, int r, int &cur, int pre, int pos)
{
    T[++tot] = T[pre];
    cur = tot;
    T[cur].cnt++;
    if (l == r) return;
    int mid = (l + r) >> 1;
    if (pos <= mid) insert(l, mid, T[cur].lc, T[pre].lc, pos);
    else insert(mid + 1, r, T[cur].rc, T[pre].rc, pos);
}
int query(int l, int r, int x, int y, int k)
{
    if (r <= k) return T[y].cnt - T[x].cnt;
    if (l == r){
        return T[y].cnt - T[x].cnt;
    }
    int s = T[T[y].lc].cnt - T[T[x].lc].cnt;
    int mid = (l + r) >> 1;
    if (k <= mid){
        return query(l, mid, T[x].lc, T[y].lc, k);
    }
    else{
        return s + query(mid + 1, r, T[x].rc, T[y].rc, k);
    }
}
int main()
{
    int T;
    scanf("%d", &T);
    for (int t = 1; t <= T; t++)
    {
        int mx = 0;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++)
            scanf("%d", &a[i]),mx=max(mx,a[i]);
        tot = 0;
        build(root[0], 1, mx);
        for (int i = 1; i <= n; i++)
            insert(1, mx, root[i], root[i - 1], a[i]);
        int lst=0;
        while (m--)
        {
            int l, r, p, k;
            scanf("%d%d%d%d", &l, &r, &p, &k);
            l ^= lst, r ^= lst, k ^= lst, p ^= lst;
            int L=0, R = 1e6;
            while (L < R)
            {
                int mid = (L + R) >> 1;
                int cnt = query(1, mx, root[l - 1], root[r], p + mid);
                if (p - mid - 1>0) cnt -= query(1, mx, root[l - 1], root[r], p - mid - 1);
                if (cnt >= k) R = mid;
                else L = mid + 1;
            }
            printf("%d\n", lst = L);
        }
    }
    return 0;
}
Last modification:August 16th, 2019 at 12:55 pm
如果觉得我的文章对你有用,请随意赞赏

One comment

  1. tomaito Google Chrome 76.0.3809.100 Windows 10

    滴!访客卡!请上车的乘客系好安全带,现在是:Thu Aug 15 2019 23:27:01 GMT+0800 (中国标准时间)

Leave a Comment