http://acm.hdu.edu.cn/showproblem.php?pid=6621
You have an array: a1, a2, , an and you must answer for some queries.
For each query, you are given an interval [L, R] and two numbers p and K. Your goal is to find the Kth closest distance between p and aL, aL+1, …, aR.
The distance between p and ai is equal to |p - ai|.
For example:
A = {31, 2, 5, 45, 4 } and L = 2, R = 5, p = 3, K = 2.
|p - a2| = 1, |p - a3| = 2, |p - a4| = 42, |p - a5| = 1.
Sorted distance is {1, 1, 2, 42}. Thus, the 2nd closest distance is 1.
Input
The first line of the input contains an integer T (1 <= T <= 3) denoting the number of test cases.
For each test case:
冘The first line contains two integers n and m (1 <= n, m <= 10^5) denoting the size of array and number of queries.
The second line contains n space-separated integers a1, a2, …, an (1 <= ai <= 10^6). Each value of array is unique.
Each of the next m lines contains four integers L’, R’, p’ and K’.
From these 4 numbers, you must get a real query L, R, p, K like this:
L = L’ xor X, R = R’ xor X, p = p’ xor X, K = K’ xor X, where X is just previous answer and at the beginning, X = 0.
(1 <= L < R <= n, 1 <= p <= 10^6, 1 <= K <= 169, R - L + 1 >= K).
Output
For each query print a single line containing the Kth closest distance between p and aL, aL+1, …, aR.
Sample Input
1
5 2
31 2 5 45 4
1 5 5 1
2 5 3 2
Sample Output
0
1
题目大意:给一个序列
a
a
a,每次询问给出四个数
L
、
R
、
P
、
K
L、R、P、K
L、R、P、K,设上一次询问的的答案为
a
n
s
ans
ans,做操作:
L
⊕
a
n
s
,
R
⊕
a
n
s
,
P
⊕
a
n
s
,
K
⊕
a
n
s
L\oplus ans,R\oplus ans,P\oplus ans,K\oplus ans
L⊕ans,R⊕ans,P⊕ans,K⊕ans后,计算新序列:
∣
P
−
a
L
∣
,
∣
P
−
a
L
+
1
∣
,
…
…
,
∣
P
−
a
R
∣
|P-a_{L}|,|P-a_{L+1}|,……,|P-a_{R}|
∣P−aL∣,∣P−aL+1∣,……,∣P−aR∣中第
K
K
K小的数。
思路:正解应该是主席树+二分。但是当时满脑子只有暴力,而划分树求第
k
k
k小又比主席树快了很多,于是就有了划分树+暴力的做法。考虑找到一个位置
p
o
s
pos
pos满足:
a
p
o
s
<
=
P
a_{pos}<=P
apos<=P且
a
p
o
s
+
1
>
P
a_{pos+1}>P
apos+1>P,然后就从
p
o
s
pos
pos这个位置开始向两端暴力枚举即可。这个
p
o
s
pos
pos可以通过二分得到。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100005
#define MID ((l+r)>>1)
int a[N],s[N],tree[20][N],num[20][N],n,m;
void Build(int c,int l,int r)
{
int lm=MID-l+1,lp=l,rp=MID+1;
for(int i=l;i<=MID;i++) //左侧与中位数相等的数的个数
lm-=s[i]<s[MID];
for(int i=l;i<=r;i++)
{
if(i==l)
num[c][i]=0;
else
num[c][i]=num[c][i-1];
if(tree[c][i]==s[MID])//中位数
{
if(lm)//左侧还要放
{
lm--;
num[c][i]++;
tree[c+1][lp++]=tree[c][i];
}
else
tree[c+1][rp++]=tree[c][i];
}
else if(tree[c][i]<s[MID])
{
num[c][i]++;
tree[c+1][lp++]=tree[c][i];
}
else
tree[c+1][rp++]=tree[c][i];
}
if(l<r)
Build(c+1,l,MID),Build(c+1,MID+1,r);
}
int query(int c,int l,int r,int ql,int qr,int k)
{
if(l==r)
return tree[c][l];
int s,ss;
if(l==ql)
s=0,ss=num[c][qr];
else
s=num[c][ql-1],ss=num[c][qr]-num[c][ql-1];
if(k<=ss)
return query(c+1,l,MID,l+s,l+s+ss-1,k);
else
return query(c+1,MID+1,r,MID+1+ql-l-s,MID+1+qr-l-s-ss,k-ss);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
s[i]=tree[0][i]=a[i];
}
sort(s+1,s+1+n);
Build(0,1,n);
int L,R,md,tmp,l,r,p,k,cnt,ans=0;
for(int i=1;i<=m;i++)
{
scanf("%d %d %d %d",&l,&r,&p,&k);
l^=ans,r^=ans,p^=ans,k^=ans;
L=1,R=r-l+1;
while(L<=R)
{
md=(L+R)>>1;
tmp=query(0,1,n,l,r,md);
if(tmp<=p)
L=md+1;
else
R=md-1;
}
if(R<=0)//p al …… ar
ans=query(0,1,n,l,r,k)-p;
else if(R>=r-l+1)//al …… ar p
ans=p-query(0,1,n,l,r,r-l-k+2);
else
{
cnt=0;
int i=R,j=R+1;
int tmp1,tmp2;
tmp1=query(0,1,n,l,r,i);
tmp2=query(0,1,n,l,r,j);
while(cnt<k)
{
if(p-tmp1<=tmp2-p)
{
++cnt;
ans=p-tmp1;
--i;
if(i>=1)
tmp1=query(0,1,n,l,r,i);
else
tmp1=-INF;
}
else
{
++cnt;
ans=tmp2-p;
++j;
if(j<=r-l+1)
tmp2=query(0,1,n,l,r,j);
else
tmp2=INF;
}
}
}
printf("%d\n",ans);
}
}
return 0;
}