多校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 = 110000;
const int M = 2000000;

int nodes;
int b[N], id[N];
int tot, K;

int T[M],lson[M],rson[M],t[M];



inline void up(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)up(x,l,m,lson[pos],lson[pos]);
    else up(x,m+1,r,rson[pos],rson[pos]);
}

void qsum(int L,int R,int x,int y,int l,int r)
{
    if(tot>=K)return ;
    
    if(L<=l&&r<=R)
    {
        tot+=t[y]-t[x];return ;
    }
    int m=l+r>>1;
    if(L<=m)qsum(L,R,lson[x],lson[y],l,m);
    if(R>m)qsum(L,R,rson[x],rson[y],m+1,r);
}
 


int main() {
    int ncase; cin>>ncase;
    while (ncase--) {
        int prv = 0;
        int n, m; scanf("%d%d",&n,&m);
        for (int i = 1; i <= n; i++) scanf("%d",&b[i]), id[i] = i;
        sort(id + 1, id + n + 1, [](int i, int j) { return b[i] < b[j]; });
        sort(b + 1, b + n + 1);
        
        ncnt = 0;
        
        for (int i = 1; i <= n; i++)up(id[i],  1,n,    T[i-1],T[i]);   //root[i] = modify(1, 1, n, id[i], root[i - 1]);
        
        for (int i = 1; i <= m; i++) {
            int L, R, p; 
            scanf("%d%d%d%d",&L,&R,&p,&K);
            L ^= prv, R ^= prv, p ^= prv, K ^= prv;
            
            int st = -1, en = 1e8;
            while (en - st > 1) {
                int mid = st + en >> 1;
                int l = lower_bound(b + 1, b + n + 1, p - mid) - b;
                int r = upper_bound(b + 1, b + n + 1, p + mid) - b - 1;
                tot = 0;
            
                qsum(L,R,T[l-1],T[r],1,n);
                if (tot >= K) en = mid;
                else st = mid;
            }
            prv = en;
            printf("%d\n",en);
        }
    }
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/bxd123/p/11279626.html