LeetCode 327. Count of Range Sum(线段树)

  • 2020 年 3 月 17 日
  • 筆記

题意:找出所有区间和在某个范围之内的个数

题解:区间问题用线段树来做。首先n^2 可以遍历所有的区间,这样会超时。

       我们用线段树,期望可以在遍历整个线段树的过程中把问题解决掉,遍历整个线段树的效率是O(n*logn) 如果遍历每个节点上的区间上所花的时间是n*logn,也可以接受,总的效率就是O(n*logn*logn)           线段树每个节点,存储这个区间的前缀区间和,和后缀区间和,而且要是排好序的。           父节点的区间个数,需要计算它的两个子节点中,左子节点的后缀区间和和右子节点的前缀区间和,相加有没有符合条件的。也就是两个排好序的数组,求两个数组里两个数字之和在某个范围的组合的个数。这里可以用n*logn的方法解决。         同时父亲节点的前缀区间和和后缀区间和,也要由两个子节点得来,使用归并排序,O(n)。           另外一定要注意,vector 超时,只能用数组了。
typedef long long int _int;    class Solution {  public:      _int* l[10005*17];      _int* r[10005*17];      int sizel[10005*17];      int sizer[10005*17];      _int range[10005*17];      vector<int> num;      _int low;      _int upp;      _int ans;      int countRangeSum(vector<int>& nums, int lower, int upper) {            if(nums.size()==0)              return 0;            low = lower;          upp = upper;          num = nums;          build(1,0,nums.size()-1);            return ans;      }        int fun(int node,_int* a,int lena,_int* b,int lenb,int y,_int* &c)      {          _int x = range[y];          int i=0,j=0;          c = new _int[lena+ lenb];          int pos=0;          while(i<lena||j<lenb)          {              if(i>=lena)              {                  c[pos++]=b[j];                  j++;                  continue;              }              if(j>=lenb)              {                  c[pos++]=a[i]+x;                  i++;                  continue;              }                _int p = a[i]+x;              _int q = b[j];                if(p < q)              {                  c[pos++]=p;                  i++;              }              else              {                  c[pos++]=q;                  j++;              }          }          return lena+lenb;      }        void pushup(int node)      {            sizer[node]=fun(node,r[node<<1],sizer[node<<1],r[node<<1|1],sizer[node<<1|1],node<<1|1,r[node]);          sizel[node]=fun(node,l[node<<1|1],sizel[node<<1|1],l[node<<1],sizel[node<<1],node<<1,l[node]);            int len = sizel[node<<1|1];          for(int i=0;i<len;i++)          {              int pos2 = upper_bound(r[node<<1],r[node<<1]+sizer[node<<1],upp-l[node<<1|1][i])-r[node<<1];              if(pos2==0)                  break;                int pos = lower_bound(r[node<<1],r[node<<1]+sizer[node<<1],low-l[node<<1|1][i])-r[node<<1];                ans+=pos2-pos;          }            range[node]=range[node<<1]+range[node<<1|1];        }        void build(int node,int start,int end)      {          if(start==end)          {              l[node]=new _int{num[start]};              sizel[node]=1;              r[node]=new _int{num[start]};              sizer[node]=1;              range[node]=num[start];                if(range[node]<=upp&&range[node]>=low)                  ans++;                return;          }            int mid = (start+end)>>1;          build(node<<1,start,mid);          build(node<<1|1,mid+1,end);            pushup(node);      }  };