题目
K-th Closest Distance
http://acm.hdu.edu.cn/showproblem.php?pid=6621
题意
给一个数组,每次给 l ,r, p, k,问区间 [l, r] 的数与 p 的绝对值的第 k 小,这个绝对值答案ans是多少。然后每次算出ans后,每次一的 l ,r, p, k都要取和ans异或出来的的值。l ^= ans, r ^= ans, p ^= ans, k ^= ans。ans一开始默认为0
题解
看到区间求第k小很容易想到用主席树,我们先设ans就是我二分的时候要找到的答案,那么就有 | p - an | = ans, 则有两种情况 p - an = ans , an - p = ans, 那么可以确定 an 的值域 [ p - ans, p + ans ]。
我们可以查询区间<= k 的数的个数,然后分别查询这两个值,做差就得到了 [p - ans, p + ans] 中有多少个数,如果个数 >= k,这个ans就是合法的。
代码
#include<stdio.h>
#include<vector>
#include<algorithm>
#include<math.h>
#define ll long long
using namespace std;
const int maxn = 2e5+5;
const int INF = 1e6+7;
struct node{
int l,r,sum;
}hjt[maxn*55];
int cnt,root[maxn];
int a[maxn];
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 x,int y)
{
if(x <= l && r <= y)
return hjt[R].sum - hjt[L].sum;
int mid = (l+r) >> 1;
int res = 0;
if(x <= mid)
{
res += query(l,mid,hjt[L].l,hjt[R].l,x,y);
}
if(y > mid)
{
res += query(mid+1,r,hjt[L].r,hjt[R].r,x,y);
}
return res;
}
int main()
{
int n,m;
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
insert(1,INF,root[i-1],root[i],a[i]);
}
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 pl = 0, pr = INF;
while(pl <= pr)
{
int mid = (pl + pr) >> 1;
if(query(1,INF,root[l-1],root[r],max(1, p - mid), min(INF, p + mid)) >= k)
{
ans = mid;
pr = mid-1;
}
else
pl = mid+1;
}
printf("%d\n",ans);
}
}
return 0;
}