多校4 K-th Closest Distance 主席树 二分答案

  题意:  给定一个序列 ai     有m个询问 l r p k  问区间l r 内  与p距离(绝对值差) 的第k小

比赛的时候   二分找到p在lr区间所处的位置     然后左右k遍历 疯狂超时   

复杂度可以去掉一个k 

直接二分答案  

主席树维护  l r 区间里  [p-mid,p+mid] 的个数  即可

注意这种主席树的经典维护方式!!!!!!区间内维护   ai 属于【x,y】的个数

普通主席树是离散化然后扔进去   T 为 区间下标

这种是以数据从小到大的位次为T 

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+100;
int lson[N<<5],rson[N<<5],T[N],t[N<<5],ncnt;

void update(int x,int l,int r,int pre,int &pos) {
    pos=++ncnt;
    lson[pos]=lson[pre]; rson[pos]=rson[pre];
    t[pos]=t[pre]+1;
    if(l==r) return ;
    int m=l+r>>1;
    if(x<=m) update(x,l,m,lson[pre],lson[pos]);
    else update(x,m+1,r,rson[pre],rson[pos]);
}

int qnum(int L,int R,int l,int r,int pre,int pos) {
    if(L<=l&&r<=R) return t[pos]-t[pre];
    int m=l+r>>1,ans=0;
    if(L<=m) ans+=qnum(L,R,l,m,lson[pre],lson[pos]);
    if(R>m) ans+=qnum(L,R,m+1,r,rson[pre],rson[pos]);
    return ans;
}

int n,m,l,r,k,x,p;
int main() {
    int cas;cin>>cas;
    while(cas--) {
        scanf("%d%d",&n,&m);
        ncnt=0;
        for(int i=1;i<=n;i++) scanf("%d",&x), update(x,1,1000000,T[i-1],T[i]);
        int lastans=0;
        while(m--) {
            scanf("%d%d%d%d",&l,&r,&p,&k);
            l^=lastans;r^=lastans;p^=lastans;k^=lastans;
            int L=0,R=1e9,ans=0;
            while(L<=R) {
                int mid=L+R>>1;
                if(qnum(max(1,p-mid),min(1000000,p+mid),1,1000000,T[l-1],T[r])>=k)R=mid-1,ans=mid;
                else L=mid+1;
            }
            printf("%d
",lastans=ans);
        }
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/bxd123/p/11279626.html