2019杭电多校赛第四场 HDU6621 K-th Closest Distance 主席树 二分

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6621

题意:T(3)组样例,n(1e5)个数,q(1e5)次查询,查询[l , r] 内, | a[i] - p | 第k大的数,且强制要求离线化

分析:初始的思路是跟着修改,想着用动态主席树来做,但是并不会,而且也很慢,事实上完全可以通过静态主席树来做

主席树的结点直接就是1e6个值,不需要进行离散化,我们是对每个值都单独统计出现的次数的

用二分,查询(p-mid,p+mid)中数的个数,具体实现看代码,复杂度为O(q*log(m)*log(m)),查询代码改的有点像线段树区间求和了,可以帮助理解

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int mod=1e9+7;
const int maxn=1e5+7;
const int maxm=1e4+7;
const int  inf=1<<30;
const int M=1e6;
const double pi=acos(-1);
int nodeNum;                                          
int L[maxn<<6],R[maxn<<6],sum[maxn<<6];                          
int a[maxn];                                                           
int T[maxn];                                                                      

int read()                                               
{                                                         
    int ans=0,flag=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') flag=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {ans=(ans<<3)+(ans<<1)+ch-'0';ch=getchar();}
    return ans*flag;
}                                   
int update(int pre,int l,int r,int x) //pre为旧树该位置节点的编号
{
    int num=++nodeNum; 
    L[num]=L[pre];R[num]=R[pre];sum[num]=sum[pre]+1;
    
    if(l!=r)
    {
        int m=(l+r)>>1;
        if(x<=m) L[num]=update(L[pre],l,m,x);
        else R[num]=update(R[pre],m+1,r,x);
    }
    return num;
}

int query(int u,int v,int l,int r,int pl,int pr) 
{
    if(l>=pl&&r<=pr) return sum[v]-sum[u];
    int res=0;
    int mid=(l+r)>>1;
    if(pl<=mid) res+=query(L[u],L[v],l,mid,pl,pr);
    if(pr>mid) res+=query(R[u],R[v],mid+1,r,pl,pr);
    return res;
}

int main(){
    int Test;Test=read();
    while(Test--){
        int n,m;n=read();m=read();
        for(int i=1;i<=n;i++){
            a[i]=read();
            T[i]=update(T[i-1],1,M,a[i]);
        }
        int ans=0;
        while(m--){
            int l,r,p,k;l=read();r=read();p=read();k=read();
            l=l^ans,r=r^ans,p=p^ans,k=k^ans;
            int left=0,right=M;
            while(left<=right){
                int mid=(left+right)>>1;
                if(query(T[l-1],T[r],1,M,max(1,p-mid),min(M,p+mid))>=k){
                    ans=mid;
                    right=mid-1;
                }
                else left=mid+1;
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/qingjiuling/p/11298609.html