hdu 6621(主席树模板)

主席树解决HDU6621
本文介绍了一种使用主席树解决HDU6621问题的方法,通过枚举p的左右范围并利用主席树进行二分查找,有效地解决了每次查询第k小元素的问题。文章详细展示了代码实现过程,包括节点结构定义、树的构建、更新和查询操作。

hdu 6621

 

思路:

每次查询第k小,只有p在改变,所以我们可以枚举p的左右范围,因为题目中保证每个值都不同,

所以省略离散化,直接建立主席树,二分寻找p的左右范围,就是最终的答案。

 

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
int a[maxn],n,m,cnt,root[maxn];
struct Node
{
    int l,r,sum;
}Tree[maxn*40];
vector <int> vc;
int getid(int x)
{
    return lower_bound(vc.begin(),vc.end(),x)-vc.begin()+1;
}
void build(int &rt,int l,int r)
{
    rt = ++cnt;
    Tree[rt].sum = 0;
    if(l==r) return ;
    int mid = (l+r)>>1;
    build(Tree[rt].l,l,mid);
    build(Tree[rt].r,mid+1,r);
}
void update(int num,int &rt,int lt,int l,int r)
{
    rt = ++cnt;
    Tree[rt] = Tree[lt];
    Tree[rt].sum++;
    if(l==r) return ;
    int mid = (l+r)>>1;
    if(num<=mid) update(num,Tree[rt].l,Tree[lt].l,l,mid);
    else update(num,Tree[rt].r,Tree[lt].r,mid+1,r);
}
int query(int i,int j,int k1,int k2,int l,int r)
{
    if(k1<=l&&r<=k2)
    {
        return Tree[j].sum-Tree[i].sum;
    }
    int mid = (l+r)>>1,ans = 0;
    if(k1<=mid) ans += query(Tree[i].l,Tree[j].l,k1,k2,l,mid);
    if(k2>mid) ans += query(Tree[i].r,Tree[j].r,k1,k2,mid+1,r);
    return ans;
}
int main(void)
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        cnt = 0;
        scanf("%d%d",&n,&m);
        build(root[0],1,maxn);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            update(a[i],root[i],root[i-1],1,maxn);
        }
        int ans = 0;
        while(m--)
        {
            int l,r,p,k;
            scanf("%d%d%d%d",&l,&r,&p,&k);
            l ^= ans;r ^= ans;
            p ^= ans;k ^= ans;
            int L = 0,R = maxn;
            while(L<=R)
            {
                int mid = (L+R)>>1;
                if(query(root[l-1],root[r],max(1,p-mid),min(p+mid,maxn),1,maxn)>=k){
                    R = mid-1;
                    ans = mid;
                }
                else{
                    L = mid+1;
                }
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值