hdu 6621 (主席树)

不用离散化建立主席树,直接建树,二分绝对值ans,让主席树查找[p-ans,p+ans]之间的数是不是又k个,如果是,那么答案就是ans,加个build清空数组就从4秒到超时,虽然它确实没用。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<math.h>
#include<time.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=1e5+100;
int N=1e6;
int tot=0;
int a[maxn],s[maxn],L[maxn*21],R[maxn*21];
int sum[maxn*21],T[maxn];

//void build(int l,int r,int &rt)
//{
//    rt=++tot;
//    sum[rt]=0;
//    if(l==r)return;
//    int mid=(l+r)>>1;
//    build(l,mid,L[rt]);
//    build(mid+1,r,R[rt]);
//}

void update(int l,int r,int &rt,int pre,int x)
{
    rt=++tot;
    L[rt]=L[pre];
    R[rt]=R[pre];
    sum[rt]=sum[pre]+1;
    if(l==r)return;
    int mid=(l+r)>>1;
    if(x<=mid)update(l,mid,L[rt],L[pre],x);
    else update(mid+1,r,R[rt],R[pre],x);
}

int query(int L1,int R1,int l,int r,int tl,int tr)
{
    if(L1<=l && r<=R1)return sum[tr]-sum[tl];
    int ANS=0,mid=(l+r)>>1;
    if(L1<=mid)ANS+=query(L1,R1,l,mid,L[tl],L[tr]);
    if(R1>mid)ANS+=query(L1,R1,mid+1,r,R[tl],R[tr]);
    return ANS;
}

int jud(int x,int len,int l,int r)
{
    int L1=max(1,x-len);
    int R1=min(N,x+len);
    int k=query(L1,R1,1,N,T[l-1],T[r]);
    return k;
}

int main(){
//    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
//    clock_t st = clock();
    int t;
    scanf("%d",&t);
    while(t--){
        tot=0;
        int n,q;
        scanf("%d%d",&n,&q);
        for(int i=1;i<=n;i++){
            int x;
            scanf("%d",&x);
            update(1,N,T[i],T[i-1],x);
        }
        int ans=0;
        while(q--){
            int l,r,p,k;
            scanf("%d%d%d%d",&l,&r,&p,&k);
            l^=ans;r^=ans;p^=ans;k^=ans;
            int l1=0,r1=N;
            while(l1<r1){
                int mid=(l1+r1)>>1;
                int res=jud(p,mid,l,r);
//                if(l==2)cout<<p<<endl;
                if(res<k){
                    l1=mid+1;
                }
                else{
                    r1=mid;
                }
            }
            printf("%d\n",ans=l1);
        }
    }
//    printf("time: %.0lfms\n", (clock()-st)*1000.0 / CLOCKS_PER_SEC);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值