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;
    }
};
posted @ 2020-07-19 17:27  blueattack  阅读(360)  评论(0编辑  收藏  举报