链接:HDU6621 K-th Closest Distance
题意:
给出一段长度为
n
≤
1
0
5
n\le10^5
n≤105的序列
a
1
,
a
2
,
.
.
.
 
,
a
n
(
a
≤
1
0
6
)
a_1,a_2,...\, ,a_n(a\le10^6)
a1,a2,...,an(a≤106),有
m
≤
1
0
5
m\le 10^5
m≤105次询问:
L
  
R
  
p
  
k
L\;R\;p\;k
LRpk
问
a
L
a_L
aL~
a
R
a_R
aR中 与
p
p
p 的 第K小个 差值的绝对值 是多少?
分析:
题目给了 K ≤ 169 K\le 169 K≤169,于是一直在想着从P的左右两边找,直到查满K个,然后T到自闭(而且还难调)。
结果题解直接二分然后验证,复杂度直接不带K,好写又好调,一遍就过…
对答案进行二分,对于可能的答案 x x x,对 a L a_L aL~ a R a_R aR构成的权值线段树查找 [ p − x ,   p + x ] [p-x,\,p+x] [p−x,p+x]是否有 K K K个,若 ≥ K \ge K ≥K,令 u p = m i d − 1 up=mid-1 up=mid−1;若 < K \lt K <K,则令 l o w = m i d + 1 low=mid+1 low=mid+1,最后一次满足 ≥ K \ge K ≥K的 x x x既是答案。
得到 a L a_L aL~ a R a_R aR构成的权值线段树用主席树就行,这题 a ≤ 1 0 6 a\le 10^6 a≤106,离散化都不用,记录一下最大和最小作为左右边界就行。
以下代码:
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=1e5+50;
const int maxa=1e6+50;
int n,m,a[maxn];
int root[maxn],t[maxa<<5],ls[maxa<<5],rs[maxa<<5],cnt;
int build(int l,int r)
{
int rt=++cnt;
if(l==r)
{
t[rt]=0;
return rt;
}
int mid=(l+r)>>1;
ls[rt]=build(l,mid);
rs[rt]=build(mid+1,r);
t[rt]=t[ls[rt]]+t[rs[rt]];
return rt;
}
int updata(int l,int r,int v,int pre)
{
int rt=++cnt;
if(l==r)
{
t[rt]=t[pre]+1;
return rt;
}
ls[rt]=ls[pre],rs[rt]=rs[pre];
int mid=(l+r)>>1;
if(v<=mid)
ls[rt]=updata(l,mid,v,ls[pre]);
else
rs[rt]=updata(mid+1,r,v,rs[pre]);
t[rt]=t[ls[rt]]+t[rs[rt]];
return rt;
}
int query(int rt1,int rt2,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr)
return t[rt2]-t[rt1];
if(l>qr||r<ql)
return 0;
int mid=(l+r)>>1;
return query(ls[rt1],ls[rt2],l,mid,ql,qr)+query(rs[rt1],rs[rt2],mid+1,r,ql,qr);
}
int L,R,P,K,X;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&n,&m);
int l=maxa,r=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
l=min(l,a[i]);
r=max(r,a[i]);
}
cnt=0;
root[0]=build(l,r);
for(int i=1;i<=n;i++)
root[i]=updata(l,r,a[i],root[i-1]);
X=0;
while(m--)
{
scanf("%d %d %d %d",&L,&R,&P,&K);
L=L^X;
R=R^X;
P=P^X;
K=K^X;
int low=0,up=1e6,mid;
while(low<=up)
{
int mid=(low+up)>>1;
if(query(root[L-1],root[R],l,r,max(l,P-mid),min(r,P+mid))>=K)
{
X=mid;
up=mid-1;
}
else
low=mid+1;
}
printf("%d\n",X);
}
}
return 0;
}