|
1 | 1 | #include "public.h" |
2 | 2 |
|
3 | | -//TLE |
4 | | -//暴力O(n^2) |
| 3 | +//68ms, 13.42% |
| 4 | +//离散线段树 |
5 | 5 |
|
6 | 6 | class Solution { |
| 7 | +private: |
| 8 | + //离散化, 求某个区间内的数字的个数, update和query同时进行 |
| 9 | + map<long long, int> gblum; //离散化用:转换 |
| 10 | + long long t[50005 << 2]; //t为线段树,t的大小是a的四倍, 用来防止下标溢出RE, 线段树区间记录此区间的值数量 |
| 11 | + long long startV; //用于build, 线段树的起始值, 端点的 |
| 12 | + int rightLoc; //数据总量 |
| 13 | + |
| 14 | + void Pushup(int k) { //更新函数,这里是实现最大值 ,同理可以变成,最小值,区间和等 |
| 15 | + t[k] = t[k << 1] + t[k << 1 | 1]; |
| 16 | + } |
| 17 | + |
| 18 | + //递归方式建树 build(1,1,n); |
| 19 | + //此函数仅在main调用一次, 线段树的结构在pushup过程中不变 |
| 20 | + void build(int k, int l, int r) { //k为当前需要建立的结点,l为当前需要建立区间的左端点,r则为右端点 |
| 21 | + if (l == r) //左端点等于右端点,即为叶子节点,直接赋值即可 |
| 22 | + t[k] = startV; |
| 23 | + else { |
| 24 | + int m = l + ((r - l) >> 1); //m则为中间点,左儿子的结点区间为[l,m],右儿子的结点区间为[m+1,r] |
| 25 | + build(k << 1, l, m); //递归构造左儿子结点 |
| 26 | + build(k << 1 | 1, m + 1, r); //递归构造右儿子结点 |
| 27 | + Pushup(k); //更新父节点 |
| 28 | + } |
| 29 | + } |
| 30 | + |
| 31 | + //递归更新区间 updata(P,1,n,1);, 实际上此函数变成了单点更新:), 单点值+1 |
| 32 | + void update(int P, int l, int r, int k) { //[L,R]即为要更新的区间,l,r为结点区间,k为结点下标 |
| 33 | + if (P <= l && r <= P) { //如果当前结点的区间真包含于要更新的区间内 |
| 34 | + t[k] += 1; //这个数加一个:) |
| 35 | + } |
| 36 | + else { |
| 37 | + int m = l + ((r - l) >> 1); |
| 38 | + if (P <= m) //如果左子树和需要更新的区间交集非空 |
| 39 | + update(P, l, m, k << 1); |
| 40 | + if (m < P) //如果右子树和需要更新的区间交集非空 |
| 41 | + update(P, m + 1, r, k << 1 | 1); |
| 42 | + Pushup(k); //更新父节点 |
| 43 | + } |
| 44 | + } |
| 45 | + |
| 46 | + //递归方式区间查询 query(L,R,1,n,1); |
| 47 | + //查找[L,R]的区间和 |
| 48 | + int query(int L, int R, int l, int r, int k) { //[L,R]即为要查询的区间,l,r为结点区间,k为结点下标 |
| 49 | + if (L <= l && r <= R) //如果当前结点的区间真包含于要查询的区间内,则返回结点信息且不需要往下递归 |
| 50 | + return t[k]; |
| 51 | + else { |
| 52 | + //Pushdown(k); //每次都需要更新子树的Lazy标记, 用不到这个 |
| 53 | + int res = 0; //返回值变量,根据具体线段树查询的什么而自定义 |
| 54 | + int m = l + ((r - l) >> 1); //m则为中间点,左儿子的结点区间为[l,m],右儿子的结点区间为[m+1,r] |
| 55 | + if (L <= m) //如果左子树和需要查询的区间交集非空 |
| 56 | + res += query(L, R, l, m, k << 1); |
| 57 | + if (R > m) //如果右子树和需要查询的区间交集非空,注意这里不是else if,因为查询区间可能同时和左右区间都有交集 |
| 58 | + res += query(L, R, m + 1, r, k << 1 | 1); |
| 59 | + |
| 60 | + return res; //返回当前结点得到的信息 |
| 61 | + } |
| 62 | + } |
7 | 63 | public: |
8 | 64 | int countRangeSum(vector<int>& nums, int lower, int upper) { |
9 | | - vector<int> sums(nums.size() + 1, 0); |
| 65 | + if (nums.empty()) return 0; |
10 | 66 |
|
11 | | - int preSum = 0; |
12 | | - for (int index = 0; index < nums.size(); ++index) |
13 | | - { |
14 | | - preSum += nums[index]; |
15 | | - sums[index + 1] = preSum; |
| 67 | + //全局变量初始化 |
| 68 | + gblum.clear(); |
| 69 | + memset(t, 0, (50005 << 2) * sizeof(long long)); |
| 70 | + startV = 0; |
| 71 | + |
| 72 | + long long preSum = 0; |
| 73 | + //计算离散map, 以及数据量总数 |
| 74 | + set<long long> us; |
| 75 | + us.insert(0); |
| 76 | + for (auto& n : nums) { |
| 77 | + preSum += n; |
| 78 | + us.insert(preSum); |
| 79 | + } |
| 80 | + int index = 0; |
| 81 | + for (auto& iterus : us) { |
| 82 | + gblum[iterus] = ++index; |
16 | 83 | } |
| 84 | + rightLoc = index; |
| 85 | + |
| 86 | + //建树 |
| 87 | + this->build(1, 1, rightLoc); |
17 | 88 |
|
18 | | - int res = 0; |
| 89 | + //搞起来:) |
| 90 | + this->update(gblum.at(0), 1, rightLoc, 1); |
| 91 | + int ret = 0; |
| 92 | + preSum = 0; |
| 93 | + for (auto& n : nums) { |
| 94 | + preSum += (long long)n; |
19 | 95 |
|
20 | | - for (int st = 0; st < nums.size(); ++st) |
21 | | - { |
22 | | - for (int en = st + 1; en <= nums.size(); ++en) |
23 | | - { |
24 | | - if (((sums[en] - sums[st]) <= upper) && ((sums[en] - sums[st]) >= lower)) |
25 | | - res++; |
| 96 | + //包括n 以及至少一个前面的 |
| 97 | + //long long realLow = (long long)preSum - (long long)upper; |
| 98 | + //long long realHi = (long long)preSum - (long long)lower; |
| 99 | + |
| 100 | + auto loit = gblum.lower_bound(preSum - upper); |
| 101 | + auto hiit = gblum.upper_bound(preSum - lower); |
| 102 | + if (loit != gblum.end() && hiit != gblum.begin()) { |
| 103 | + int lowBoundV = loit->first; |
| 104 | + hiit--; |
| 105 | + int highBoundV = hiit->first; |
| 106 | + int preRet = this->query(loit->second, hiit->second, 1, rightLoc, 1); |
| 107 | + ret += preRet; |
26 | 108 | } |
| 109 | + else { //不可能找到值了! |
| 110 | + ; |
| 111 | + } |
| 112 | + this->update(gblum.at(preSum), 1, rightLoc, 1); |
27 | 113 | } |
28 | | - return res; |
| 114 | + return ret; |
29 | 115 | } |
30 | 116 | }; |
31 | 117 |
|
@@ -117,7 +203,13 @@ int main() |
117 | 203 | { |
118 | 204 | Solution* s = new Solution(); |
119 | 205 | vector<int> nums = {-2,5,-1}; |
120 | | - cout << s->countRangeSum(nums, -2, 2); |
| 206 | + cout << s->countRangeSum(nums, -2, 2) << endl; //3 |
| 207 | + vector<int> nums2 = { 0, -3, -3, 1, 1, 2 }; |
| 208 | + cout << s->countRangeSum(nums2, 3, 5) << endl; //2 |
| 209 | + vector<int> nums3 = { -2147483647, 0, -2147483647, 2147483647 }; |
| 210 | + cout << s->countRangeSum(nums3, -564, 3864) << endl; //3 |
| 211 | + vector<int> nums4 = { 2147483647,2147483647,0,-2147483647 }; |
| 212 | + cout << s->countRangeSum(nums4, 4232, 7660) << endl; //2 |
121 | 213 | return 0; |
122 | 214 | } |
123 | 215 | */ |
0 commit comments