SegmentItem find(int l, int r, int s, int t, int p){
if (l <= s && t <= r){
return tree[p];
}
int m = s + ((t - s) >>1);
SegmentItem sum;
if (r <= m) return find(l, r, s, m, p*2);
if (l > m) return find(l, r, m+1, t, p*2+1);
return find(l, r, s, m, p*2) + find(l, r, m+1, t, p*2+1);
}
intquery(int left, int right){
int sum =0;
int i = left+m; // 左閉區間
int j = right+m; // 右閉區間
for (; i <= j; i >>=1, j >>=1){
if (i &1) sum += arr[i++];
if (!(j &1)) sum += arr[j--];
}
return sum;
}
備註:開區間作法 (0-index 時會出現 -1 的情形,建議使用閉區間)
intquery(int left, int right){
int sum =0;
int i = left+m-1;
int j = right+m+1;
for(; i^j^1; i >>=1, j >>=1){
if (~i &1) sum += arr[i^1];
if (j &1) sum += arr[j^1];
}
return sum;
}
voidupdate(int left, int right, int diff){
int len =1, cntl =0, cntr =0; // cntl, cntr 是左右邊分別實際修改的區間長度
left += m-1;
right += m+1;
for (; left^right^1; left >>1, right >>1, len <<1){
arr[left] += cntl * diff;
arr[right] += cntr * diff;
if (~left &1) {
arr[left^1] += diff * len;
mark[left^1] += diff;
cntl += len;
}
if (right &1) {
arr[right^1] += diff * len;
mark[right^1] += diff;
cntr += len;
}
}
for (; left; left >>=1, right >>=1){
arr[left] += cntl * diff;
arr[right] += cntr * diff;
}
}
在有區間修改存在時,區間查詢也需要考慮標記的影響。
所以除了加上端點的兄弟節點訊息,沿途中遇到的標記也對答案有貢獻,同樣需要上推到根節點。
intquery(int left, int right){
int sum =0, len =1, cntl =0, cntr =0;
left += m -1;
right += m +1;
for (; left^right^1; left >>=1, right >>=1, len <<1){
sum += cntl * mark[left] + cntr * mark[right];
if (~left &1) sum += arr[left^1], cntl += len;
if (right &1) sum += arr[right^1], cntr += len;
}
for (; left; left >>1, right >>1){
sum += cntl * mark[left] + cntr * mark[right];
}
return sum;
}
區間查詢最大值:
voidupdate(int l, int r, int d) {
for (l += N -1, r += N +1; l ^ r ^1; l >>=1, r >>=1)
{
if (l < N) tree[l] = max(tree[l <<1], tree[l <<1|1]) + mark[l],
tree[r] = max(tree[r <<1], tree[r <<1|1]) + mark[r];
if (~l &1) tree[l ^1] += d, mark[l ^1] += d;
if (r &1) tree[r ^1] += d, mark[r ^1] += d;
}
for (; l; l >>=1, r >>=1)
if (l < N) tree[l] = max(tree[l <<1], tree[l <<1|1]) + mark[l],
tree[r] = max(tree[r <<1], tree[r <<1|1]) + mark[r];
};
intquery(int l, int r) {
int maxl =-INF, maxr =-INF;
for (l += N -1, r += N +1; l ^ r ^1; l >>=1, r >>=1)
{
maxl += mark[l], maxr += mark[r];
if (~l &1) cmax(maxl, tree[l ^1]);
if (r &1) cmax(maxr, tree[r ^1]);
}
for (; l; l >>=1, r >>=1)
maxl += mark[l], maxr += mark[r];
return max(maxl, maxr);
};
classNumArray {
classSegTree {
public:int val;
int begin, end;
SegTree* left, *right;
SegTree(int v):val(v) {}
SegTree(int v, int b, int e):val(v), begin(b), end(e) {}
SegTree(int v, int b, int e, SegTree* l, SegTree* r)
:val(v), begin(b), end(e), left(l), right(r) {}
};
SegTree* root;
SegTree*build(vector<int>& nums, int b, int e){
if (e < b) return NULL;
if (b == e) returnnew SegTree(nums[b], b, b);
int mid = b + (e-b)/2;
SegTree* left = build(nums, b, mid);
SegTree* right = build(nums, mid+1, e);
returnnew SegTree(left->val + right->val, b, e, left, right);
}
voidupdate(SegTree* node, int index, int val){
if (node->begin == index && node->end == index){
node->val = val;
} else {
int mid = node->begin + (node->end - node->begin)/2;
if (index <= mid){
update(node->left, index, val);
} else {
update(node->right, index, val);
}
node->val = node->left->val + node->right->val;
}
}
intquery(SegTree* node, int left, int right){
if (node->begin == left && node->end == right){
return node->val;
}
int mid = node->begin + (node->end - node->begin)/2;
if (right <= mid){
return query(node->left, left, right);
} elseif (left > mid){
return query(node->right, left, right);
}
return query(node->left, left, mid) + query(node->right, mid+1, right);
}
public: NumArray(vector<int>& nums) {
root = build(nums, 0, nums.size()-1);
}
voidupdate(int index, int val) {
update(root, index, val);
}
intsumRange(int left, int right) {
return query(root, left, right);
}
};
zkw 線段樹
classNumArray {
classSegTree {
vector<int> arr;
int m, n;
public: SegTree(vector<int>& nums) {
n = nums.size();
for (m =1; m < n; m <<=1);
build(nums);
}
voidbuild(vector<int>& nums) {
arr.assign(2*m, 0);
for (int i =0; i < n; ++i) arr[m+i] = nums[i];
for (int i = m-1; i; --i) arr[i] = arr[i<<1] + arr[i<<1|1];
}
voidupdate(int index, int val) {
int diff = val - arr[m+index];
for (index += m; index; index >>=1) arr[index] += diff;
}
intquery(int left, int right) {
int sum =0;
for (int i = left+m, j = right+m; i <= j; i >>=1, j >>=1){
if (i &1) sum += arr[i++];
if (!(j &1)) sum += arr[j--];
}
return sum;
}
};
public: SegTree* root;
NumArray(vector<int>& nums) {
root =new SegTree(nums);
}
voidupdate(int index, int val) {
root->update(index, val);
}
intsumRange(int left, int right) {
return root->query(left, right);
}
};