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

题意:

给你一个数组,q次询问,每次问你[l,r]范围内与p距离第k大的元素的与p的距离,强制在线

思路:

主席树提取出[l,r]内的权值线段树,然后二分与p的距离mid

ask该权值线段树里[p-mid,p+mid]的数的个数,使其刚好大于等于k

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<deque>
#include<set>
#include<vector>
#include<map>

#define fst first
#define sc second
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lc root<<1
#define rc root<<1|1

using namespace std;

typedef double db;
typedef long double ldb;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef pair<ll,ll> PLL;

const db eps = 1e-6;
const int mod = 1e9+7;
const int maxn = 2e7+2e6+100;
const int maxm = 4e6+100;
const int inf = 0x3f3f3f3f;
const db pi = acos(-1.0);

int ls[maxn],rs[maxn],dat[maxn];
int tot;
int n,q;
int a[maxm];
int root[maxm];
int t;
int insert(int now, int l, int r, int x, int val){
    int p = ++tot;
    ls[p]=ls[now];rs[p]=rs[now];dat[p]=dat[now];
    if(l==r){
        dat[p]+=val;
        return p;
    }
    int mid = (l+r)>>1;
    if(x<=mid)ls[p]=insert(ls[now],l,mid,x,val);
    else rs[p]=insert(rs[now],mid+1,r,x,val);
    dat[p]=dat[ls[p]]+dat[rs[p]];
    return p;
}
int ask(int lst, int now, int l, int r, int L, int R){
    //printf("%d %d %d %d %d %d\n",lst,now,l,r,L,R);
    int mid = (l+r)>>1;
    int ans = 0;
    if(L<=l&&r<=R)return dat[now]-dat[lst];
    if(L<=mid)ans+=ask(ls[lst],ls[now],l,mid,L,R);
    if(mid<R)ans+=ask(rs[lst],rs[now],mid+1,r,L,R);
    return ans;
}
int K,p;
bool cmp(int a, int b){
    return abs(a-p)<abs(b-p);
}

int main(){
    scanf("%d", &t);

    while(t--){
        int lstans = 0;
        mem(dat,0);
        tot=0;
        scanf("%d %d", &n, &q);
        for(int i = 1; i <= n; i++){
            scanf("%d", &a[i]);
            root[i]=insert(root[i-1],1,1000000,a[i],1);
        }



        while(q--){
            int l, r;
            scanf("%d %d %d %d", &l, &r, &p, &K);
            l^=lstans;
            r^=lstans;
            p^=lstans;
            K^=lstans;
            int ans;
            int L = 0;
            int R = 1000000;
            while(L<=R){
                int mid = (L+R)>>1;
                int res = ask(root[l-1],root[r],1,1000000,max(1,p-mid),min(1000000,p+mid));
                if(res>=K){
                    ans=mid;
                    R=mid-1;
                }
                else L=mid+1;
            }
            lstans=ans;
            printf("%d\n",ans);

        }
    }
    return 0;
}
/*
1
5 2
31 2 5 45 4
1 5 5 1
2 5 3 2

 */

猜你喜欢

转载自www.cnblogs.com/wrjlinkkkkkk/p/11278800.html