这是按照http://blog.csdn.net/thestoryofsnow/article/details/40942009刷的第4道题,感觉难度已经上来了。看到题目就知道可以用segment tree,于是按照geeksforgeeks的方法做了实现:http://www.geeksforgeeks.org/segment-tree-set-1-sum-of-given-range/。然后就是一系列的WA, RE和TLE。主要原因是不熟悉64位int的表示方法。POJ不认识stdint.h,按照报错google了下似乎是windows服务器。RE是之前没有理解对segment tree的最大index的范围。实际上,对于有n个leaf(实际需要保存的数),那么中间节点为n-1个,所以总结点是2n-1个。但是由于segment tree是full binary tree但不是complete binary tree,所以array中有些段是空的,index的最大范围是2 * (N + (N - 1) - 1) + 2 + 1 = 4 * N - 1(这个数应该是取不到的)。所以我最后开了4N的空间。
TLE则是算法的问题了。naive的方法更新的代价很大,实际上要修改涉及到的每个节点,所以比正常的array update开销还大。
参考了
【1】http://blog.sina.com.cn/s/blog_5d34cc430100f0d1.html
【2】http://my.oschina.net/Alexanderzhou/blog/204116
的实现,上面都用的是“延迟更新”的方法,就是把需要更新的值加到delta里面,需要的时候才向下传递。我用的是【1】里面的实现,代码注释写得很好,容易理解。
最后AC了。但显然是擦着边过的,几乎是所有实现中最慢的。我猜和动态分配空间而不是一开始静态分配好及参数传递开销等有关,但主要还是算法实现上面的。目前的实现的好处是自己能够理解,并写出来。AC了也就不想改了。discuss里面提出了很多第一次听说,更别提实现的数据结构,看AC的时间,大神们还有1s多一点过的,程序差距不是一点半点。
Accepted | 6908K | 4391MS | C++ | 3694B |
/* ID: thestor1 LANG: C++ TASK: poj3468 */ #include <iostream> #include <fstream> #include <cmath> #include <cstdio> #include <cstring> #include <limits> #include <string> #include <vector> #include <list> #include <set> #include <map> #include <queue> #include <stack> #include <algorithm> #include <cassert> using namespace std; int N; class Segment { public: long long sum, delta; Segment(): sum(0), delta(0) {} }; long long int buildSegmentTree(vector<Segment> &segmentTree, int left, int right, int index, const vector<int> &nums) { // cout << "[debug]left: " << left << ", right: " << right << ", index: " << index << endl; segmentTree[index].delta = 0; if (left == right) { // assert (index < 4 * N - 1); segmentTree[index].sum = nums[left]; return segmentTree[index].sum; } int mid = left + (right - left) / 2; // assert (index < 4 * N - 1); segmentTree[index].sum = buildSegmentTree(segmentTree, left, mid, 2 * index + 1, nums) + buildSegmentTree(segmentTree, mid + 1, right, 2 * index + 2, nums); return segmentTree[index].sum; } long long int getSum(vector<Segment> &segmentTree, int left, int right, const int lindex, const int rindex, int index) { if (lindex <= left && right <= rindex) { return segmentTree[index].sum + segmentTree[index].delta * (right - left + 1); } if (lindex > right || rindex < left) { return 0; } int mid = left + (right - left) / 2; if (segmentTree[index].delta) { // assert (2 * index + 2 < 4 * N - 1); segmentTree[2 * index + 1].delta += segmentTree[index].delta; segmentTree[2 * index + 2].delta += segmentTree[index].delta; segmentTree[index].sum += segmentTree[index].delta * (right - left + 1); segmentTree[index].delta = 0; } return getSum(segmentTree, left, mid, lindex, rindex, 2 * index + 1) + getSum(segmentTree, mid + 1, right, lindex, rindex, 2 * index + 2); } void update(vector<Segment> &segmentTree, int left, int right, const int lindex, const int rindex, int index, const long long int diff) { if (lindex > right || rindex < left) { return; } if (lindex <= left && right <= rindex) { // assert (index < 4 * N - 1); segmentTree[index].delta += diff; return; } int oleft = max(left, lindex), oright = min(right, rindex); // assert (index < 4 * N - 1); segmentTree[index].sum += diff * (oright - oleft + 1); // assert (left != right); int mid = left + (right - left) / 2; update(segmentTree, left, mid, lindex, rindex, 2 * index + 1, diff); update(segmentTree, mid + 1, right, lindex, rindex, 2 * index + 2, diff); } void printSegmentTree(const vector<Segment> &segmentTree) { cout << "segmentTree:" << endl; for (int i = 0; i < segmentTree.size(); ++i) { cout << i << ": " << segmentTree[i].sum << ", "; } cout << endl; } int main() { int Q; cin >> N >> Q; vector<int> nums(N); for (int i = 0; i < N; ++i) { cin >> nums[i]; } // 2 * (N + (N - 1) - 1) + 2 + 1 = 4 * N - 1 vector<Segment> segmentTree(4 * N); buildSegmentTree(segmentTree, 0, N - 1, 0, nums); // printSegmentTree(segmentTree); for (int i = 0; i < Q; ++i) { char type; int lindex, rindex; long long int diff; cin >> type; // cout << "type:" << type << endl; if (type == 'Q') { cin >> lindex >> rindex; // 1-based to 0-based lindex--; rindex--; cout << getSum(segmentTree, 0, N - 1, lindex, rindex, 0) << endl; } else { cin >> lindex >> rindex >> diff; // 1-based to 0-based lindex--; rindex--; update(segmentTree, 0, N - 1, lindex, rindex, 0, diff); } } return 0; }