hdu 6621 K-th Closest Distance 杭电多校第4场

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

队友一上来分块RE了一发,搞得我也想分块,结果lts一声主席树,然后就发现是主席树板题了。。。

直接权值主席树,下标表示值,记录的sum表示当前值的个数就行了,然后二分答案,得到上下界,用rt[r]-rt[l-1]去找就行了。

#include<bits/stdc++.h>
#define maxl 100010
using namespace std;

const int nn=1e6;

int n,m,tot,ans;
int rt[maxl],a[maxl];
struct node
{
    int ls,rs,sum;
}tree[maxl*10*35];

inline void insert(int num,int &x,int l,int r)
{
    tree[++tot]=tree[x];x=tot;
    ++tree[x].sum;
    if(l==r) return;
    int mid=(l+r)>>1;
    if(num<=mid)
        insert(num,tree[x].ls,l,mid);
    else
        insert(num,tree[x].rs,mid+1,r);
}

inline void prework()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    tree[0].ls=tree[0].rs=tree[0].sum=0;
    rt[0]=0;
    tot=0;
    for(int i=1;i<=n;i++)
    {
        rt[i]=rt[i-1];
        insert(a[i],rt[i],1,nn);
    }
}

inline int query(int i,int j,int l,int r,int i1,int j1)
{
    if(i1==l && j1==r)
        return tree[j].sum-tree[i].sum;
    int mid=(i1+j1)>>1,ret;
    if(r<=mid)
        ret=query(tree[i].ls,tree[j].ls,l,r,i1,mid);
    else if(l>mid)
        ret=query(tree[i].rs,tree[j].rs,l,r,mid+1,j1);
    else
    {
        ret=query(tree[i].ls,tree[j].ls,l,mid,i1,mid);
        ret+=query(tree[i].rs,tree[j].rs,mid+1,r,mid+1,j1);
    }
    return ret;
}

inline bool jug(int l,int r,int mid,int p,int k)
{
    int up=min(p+mid,nn),lo=max(1,p-mid);
    int sum=query(rt[l-1],rt[r],lo,up,1,nn);
    if(sum<k)
        return false;
    else
        return true;
}

inline void mainwork()
{
    ans=0;int up,lo,p,k,l,r,mid;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d%d",&lo,&up,&p,&k);
        lo^=ans;up^=ans;p^=ans;k^=ans;
        l=0;r=nn;
        while(l+1<r)
        {
            mid=(l+r)>>1;
            if(!jug(lo,up,mid,p,k))// <k
                l=mid;
            else
                r=mid;
        }
        if(jug(lo,up,l,p,k))
            ans=l;
        else
            ans=l+1;
        printf("%d\n",ans);
    }
}

inline void print(){}

int main()
{
    int t;
    scanf("%d",&t);
    for(int i=1;i<=t;i++)
    {
        prework();
        mainwork();
        print();
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值