2019HDU多校 6621 (主席树+二分)

传送门

题意就不解释了。

如果按照题意乱搞个树套树好像会T的很惨。
考虑不去修改,把绝对值看成一个值域。我们可以二分数组内元素的值,假设为 m i d mid mid, 那么我们会得到一个值域
[ p − m i d , p + m i d ] [p - mid, p+mid] [pmid,p+mid], 答案就是求给定的数组中,落在这个值域内的元素的第 k k k 大, 那么这就是个区间比 k k k小的元素个数,不就是个主席树的板子吗。

复杂度就是 O ( q l o g ( m ) l o g ( m ) O(qlog(m)log(m) O(qlog(m)log(m)

2620ms 喜提本题rank1,,,


#include<iostream>
#include<algorithm>
#include<cstdio>
#include<stdio.h>
#include<string.h>
#include<queue>
#include<cmath>
#include<map>
#include<set>
#include<vector> 
using namespace std;
#define inf 0x3f3f3f3f

#define mem(a,b) memset(a,b,sizeof(a));
#define lowbit(x)  x&-x;  
#define debugint(name,x) printf("%s: %d\n",name,x);
#define debugstring(name,x) printf("%s: %s\n",name,x);
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-6;
const int maxn = 1e5+5;
const int MAXN = 1e6;
const int mod = 1e9+7;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,m;
vector<int>v;
struct node{
    int l,r,sum;
}hjt[maxn*40];
int a[maxn],rt[maxn],cnt;

int getid(int x){return lower_bound(v.begin(),v.end(),x)-v.begin()+1;}
void insert(int l,int r,int pre,int &now,int p){
    hjt[++cnt] = hjt[pre];
    now = cnt;
    hjt[now].sum++;
    if(l == r) return;
    int mid = (l+r)>>1;
    if(p <= mid) insert(l,mid,hjt[pre].l,hjt[now].l,p);
    else insert(mid+1,r,hjt[pre].r,hjt[now].r,p);
}
int query(int l,int r,int L,int R,int k){
	if(r <= k) return hjt[R].sum - hjt[L].sum;
	int mid = (l+r)>>1;
	if(k <= mid) return query(l,mid,hjt[L].l,hjt[R].l,k);
	else return hjt[hjt[R].l].sum - hjt[hjt[L].l].sum + query(mid+1,r,hjt[L].r,hjt[R].r,k);
}
int main() {
	int t;
	cin>>t;
	
	for(int ca = 1; ca <= t; ca++){
		cnt = 0;
		scanf("%d%d",&n,&m);
		for(int i = 1; i <= n; i++)
			a[i]=read();
		for(int i = 1; i <= n; i++)
			insert(1,MAXN,rt[i-1],rt[i],a[i]);
		int L,R,p,k;
		int ans = 0;
		while(m--){
			scanf("%d%d%d%d",&L,&R,&p,&k);
			L = L^ans;
			R = R^ans;
			p = p^ans;
			k = k^ans;
			int l = 0, r = MAXN+2;
			int sum1, sum2;
			while(l <= r){
				int mid = (l+r)>>1;
				sum1 = query(1,MAXN,rt[L-1],rt[R],max(1,p-mid-1));
				sum2 = query(1,MAXN,rt[L-1],rt[R],min(MAXN,p+mid));
				if(sum2 - sum1 >= k){
					ans = mid;
					r = mid-1;
				}else{
					l = mid+1;
				}
			}
			printf("%d\n",ans);
		}
	} 
	return 0;
}
/*
5 3
1 2 3 4 5
1 5 4 1
0
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值