HDU6621 K-th Closest Distance HDU2019多校训练第四场 1008(主席树+二分)

HDU6621 K-th Closest Distance HDU2019多校训练第四场 1008(主席树+二分)

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6621

题意:

给你n个数,有m次询问

每次问你在区间[l,r]内 第k小的|(a_i-p)|是多少

题解:

主席树+二分

每次二分答案

如果p+mid到p-mid的值的个数大于k个的话,mid值就是可行了,然后缩小区间往左找即可

因为保证有解,所以二分出来的mid值就是答案了

query查的是权值在区间[p-mid,p+mid]内数的个数

主席树的sum就是用来统计权值个数的

注意不要被k给坑了,枚举第k小的数会T到爆的(QAQ)

AC单组复杂度分析 :1e5*log(1e6)*log(1e6);

TLE单组复杂度分析:1e5*169*2*log(1e6);

代码:

#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
typedef unsigned long long uLL;
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define bug printf("*********
")
#define FIN freopen("input.txt","r",stdin);
#define FON freopen("output.txt","w+",stdout);
#define IO ios::sync_with_stdio(false),cin.tie(0)
#define debug1(x) cout<<"["<<#x<<" "<<(x)<<"]
"
#define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"]
"
#define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"]
"
const int maxn = 3e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double Pi = acos(-1);
LL gcd(LL a, LL b) {
    return b ? gcd(b, a % b) : a;
}
LL lcm(LL a, LL b) {
    return a / gcd(a, b) * b;
}
double dpow(double a, LL b) {
    double ans = 1.0;
    while(b) {
        if(b % 2)ans = ans * a;
        a = a * a;
        b /= 2;
    } return ans;
}
LL quick_pow(LL x, LL y) {
    LL ans = 1;
    while(y) {
        if(y & 1) {
            ans = ans * x % mod;
        } x = x * x % mod;
        y >>= 1;
    } return ans;
}
struct Tree {
    int l, r, sum;
} T[maxn * 40];
int cnt, n, m;
int a[maxn];
int root[maxn];
void update(int l, int r, int &x, int y, int pos) {
    T[++cnt] = T[y];
    T[cnt].sum++;
    x = cnt;
    if(l == r) return;
    int mid = (l + r) >> 1;
    if(pos <= mid) update(l, mid, T[x].l, T[y].l, pos);
    else update(mid + 1, r, T[x].r, T[y].r, pos);
}
int query(int l, int r, int x, int y, int k) {
    if(k==0) return 0;
    if(l == r) return T[y].sum - T[x].sum;
    int mid = (l + r) >> 1;
    if (k <= mid)return query(l, mid, T[x].l, T[y].l, k);
    else {
        int ans = query(mid + 1, r, T[x].r, T[y].r, k);
        ans += T[T[y].l].sum - T[T[x].l].sum;
        return ans;
    }
}
int main() {

    int T;
    scanf("%d", &T);
    while(T--) {
        cnt = 0;
        scanf("%d%d", &n, &m);

        for(int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
        }
        int N = 1000000;
        for(int i = 1; i <= n; i++) {
            update(1, N, root[i], root[i - 1], a[i]);
        }
        int x, y, p, k;
        int ans = 0;
        for(int i = 1; i <= m; i++) {
            scanf("%d%d%d%d", &x, &y, &p, &k);
            x ^= ans;
            y ^= ans;
            if(x > y) swap(x, y);
            p ^= ans;
            k ^= ans;
            int l = 0, r = N;
            while(l <= r) {
                int mid = (l + r) >> 1;
                int R = min(N, p + mid);
                int L = max(0, p - mid - 1);
                if(query(1, N, root[x - 1], root[y], R) -
                        query(1, N, root[x - 1], root[y], L) >= k) {
                    ans = mid;
                    r = mid - 1;
                } else {
                    l = mid + 1;
                }
            }
            /*
             while (L <= R) {
                mid = (L + R) >> 1;
                if (query(1, N, root[l - 1], root[r], min(p + mid, N)) -
                    query(1, N, root[l - 1], root[r], max(p - mid - 1, 0)) >= k)
                    ans = mid, R = mid - 1;
                else L = mid + 1;
            }*/
            printf("%d
", ans);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/buerdepepeqi/p/11279014.html