5467. 找到最接近目标值的函数值
题目大意
寻找数组arr的区间l和r,使[l,r]区间内的数&后与target的差值的绝对值最小
思路
有一个很重要的推论就是&运算具有单调递减性,也就是ask(a,r+1)<=ask(l,r)<=ask(l+1,r)。因此我们可以通过滑动数组,当前区间结果>target时,r++;否则l++。
我们用线段树维护区间&的值
class Solution {
public:
static const int maxn=4*1e5+10;
int a[maxn];
int d[maxn];
void build(int s,int t,int p)
{
//p代表线段树的结点号,s和t描述原数组的区间
if(s==t)
{
d[p]=a[s];
return;
}
int m=(s+t)>>1;
build(s,m,2*p);
build(m+1,t,2*p+1);
d[p]=d[2*p]&d[2*p+1];
}
int ask(int l,int r,int s,int t,int p)
{
//l,r是查询区间;s,t是当前线段树的结点区间,p是线段树当前访问的结点
if(l<=s&&r>=t)
return d[p];
int m=(s+t)>>1;
if(r<=m)
return ask(l,r,s,m,2*p);
if(l>m)
return ask(l,r,m+1,t,2*p+1);
return ask(l,m,s,m,2*p)&ask(m+1,r,m+1,t,2*p+1);
}
int closestToTarget(vector<int>& arr, int target) {
int n=arr.size();
for(int i=0;i<n;i++)
a[i]=arr[i];
build(0,n-1,1);
int l=0,r=0,ans=1e9+1e7;
while(r<n)
{
int t=ask(l,r,0,n-1,1);
if(t>target)
r++;
else
l++,r=max(l,r);
ans=min(ans,abs(t-target));
}
return ans;
}
};