来源:CACC-T3
题意:
给定一个长度为
N
N
N 的数组,每次可以对数组进行以下操作:
对区间 [ s , t ] [s, t] [s,t] 内所有的奇数加上某个数,
对区间 [ s , t ] [s, t] [s,t] 内所有的偶数加上某个数,
查询区间 [ s , t ] [s, t] [s,t] 内所有数的总和。
相较于模板题目加入了对于区间内的奇数或偶数进行操作,考虑维护下面的信息:
Info:奇数个数、偶数个数、总和
Tag:奇数加什么、偶数加什么
这题主要考虑如何维护奇数和偶数添加的顺序,也就是说如何将懒标记进行合理的合并。
我们规定一个懒标记顺序:比如说我们先加偶数,再加奇数。那么当一个节点从他的父节点先接收到奇数 -3 的信息,然后接收到偶数 +20 的信息,那么对我们来说其实就等价于偶数 +20 ,然后奇数 +17 。于是将多次懒标记上的操作打包成一次操作,后续用于传递给子节点。
主要就是考虑先前两个懒标记上的奇偶性,是否引起了被加数的奇偶性发生改变,从而判断懒标记应该怎么合并。
时间复杂度: O ( ( n + m ) l o g n ) O((n+m)logn) O((n+m)logn)
#include <bits/stdc++.h>
using i64 = long long;
template<class Info, class Tag>
struct LazySegmentTree {
int n;
std::vector<Info> info;
std::vector<Tag> tag;
LazySegmentTree() : n(0) {}
LazySegmentTree(int n_, Info v_ = Info()) {
init(n_, v_);
}
template<class T>
LazySegmentTree(std::vector<T> init_) {
init(init_);
}
void init(int n_, Info v_ = Info()) {
init(std::vector(n_, v_));
}
template<class T>
void init(std::vector<T> init_) {
n = init_.size();
info.assign(4 << std::__lg(n), Info());
tag.assign(4 << std::__lg(n), Tag());
std::function<void(int, int, int)> build = [&](int p, int l, int r) {
if (r - l == 1) {
info[p] = init_[l];
return;
}
int m = (l + r) / 2;
build(2 * p, l, m);
build(2 * p + 1, m, r);
pull(p);
};
build(1, 0, n);
}
void pull(int p) {
info[p] = info[2 * p] + info[2 * p + 1];
}
void apply(int p, const Tag &v) {
info[p].apply(v);
tag[p].apply(v);
}
void push(int p) {
apply(2 * p, tag[p]);
apply(2 * p + 1, tag[p]);
tag[p] = Tag();
}
void modify(int p, int l, int r, int x, const Info &v) {
if (r - l == 1) {
info[p] = v;
return;
}
int m = (l + r) / 2;
push(p);
if (x < m) {
modify(2 * p, l, m, x, v);
} else {
modify(2 * p + 1, m, r, x, v);
}
pull(p);
}
void modify(int p, const Info &v) {
modify(1, 0, n, p, v);
}
Info rangeQuery(int p, int l, int r, int x, int y) {
if (l >= y || r <= x) {
return Info();
}
if (l >= x && r <= y) {
return info[p];
}
int m = (l + r) / 2;
push(p);
return rangeQuery(2 * p, l, m, x, y) + rangeQuery(2 * p + 1, m, r, x, y);
}
Info rangeQuery(int l, int r) {
return rangeQuery(1, 0, n, l, r);
}
void rangeApply(int p, int l, int r, int x, int y, const Tag &v) {
if (l >= y || r <= x) {
return;
}
if (l >= x && r <= y) {
apply(p, v);
return;
}
int m = (l + r) / 2;
push(p);
rangeApply(2 * p, l, m, x, y, v);
rangeApply(2 * p + 1, m, r, x, y, v);
pull(p);
}
void rangeApply(int l, int r, const Tag &v) {
return rangeApply(1, 0, n, l, r, v);
}
};
struct Tag {
i64 odd = 0;
i64 even = 0;
void apply(const Tag& t) {
if (odd % 2 == 0) {
odd += t.odd;
} else {
odd += t.even;
}
if (even % 2 == 0) {
even += t.even;
} else {
even += t.odd;
}
}
};
struct Info {
int oddNum = 0;
int evenNum = 0;
i64 sum = 0;
void apply(const Tag& t) {
int newodd = 0, neweven = 0;
if (t.even) {
sum += 1LL * evenNum * t.even;
if (t.even % 2) {
newodd += evenNum;
} else {
neweven += evenNum;
}
} else {
neweven += evenNum;
}
if (t.odd) {
sum += 1LL * oddNum * t.odd;
if (t.odd % 2) {
neweven += oddNum;
} else {
newodd += oddNum;
}
} else {
newodd += oddNum;
}
oddNum = newodd;
evenNum = neweven;
}
};
Info operator+(Info a, Info b) {
Info c;
c.oddNum = a.oddNum + b.oddNum;
c.evenNum = a.evenNum + b.evenNum;
c.sum = a.sum + b.sum;
return c;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n, m;
std::cin >> n >> m;
std::vector<Info> info(n);
for (int i = 0; i < n; i++) {
info[i] = {0, 1, 0LL};
}
LazySegmentTree<Info, Tag> seg(info);
for (int i = 0; i < m; i++) {
int f;
std::cin >> f;
if (f == 1) {
int s, t, o, y;
std::cin >> s >> t >> o >> y;
s--;
seg.rangeApply(s, t, {(o == 1) * y, (o == 0) * y});
} else {
int s, t;
std::cin >> s >> t;
s--;
std::cout << seg.rangeQuery(s, t).sum << "\n";
}
}
return 0;
}