Description
给定序列 a=(a1,a2,⋯ ,an)a=(a_1,a_2,\cdots,a_n)a=(a1,a2,⋯,an),有 mmm 个操作,分四种:
- add(l,r,v)\operatorname{add}(l,r,v)add(l,r,v):对于所有 i∈[l,r]i \in [l,r]i∈[l,r] 执行 ai←ai+va_i \gets a_i+vai←ai+v.
- mul(l,r,v)\operatorname{mul}(l,r,v)mul(l,r,v):对于所有 i∈[l,r]i \in [l,r]i∈[l,r] 执行 ai←ai×va_i \gets a_i\times vai←ai×v.
- freeze(l,r,x)\operatorname{freeze}(l,r,x)freeze(l,r,x):区间 [l,r][l,r][l,r] 在接下来的 xxx 次操作中被冻结,不会受修改操作影响,已有的冻结效果不会被替换.
- query(l,r)\operatorname{query}(l,r)query(l,r):求 (∑i=lrai) mod (109+7)(\sum\limits_{i=l}^r a_i) \bmod (10^9+7)(i=l∑rai)mod(109+7).
Limitations
1≤n,m≤2×1051 \le n,m \le 2\times 10^51≤n,m≤2×105
0≤ai,v≤109+70 \le a_i,v \le 10^9+70≤ai,v≤109+7
设当前为第 ttt 次操作,则 0≤x≤m−k0 \le x \le m-k0≤x≤m−k
1s,512MB1\text{s},512\text{MB}1s,512MB
Solution
将 freeze\operatorname{freeze}freeze 操作拆成冻结和解冻两个操作,将解冻操作按解冻时间记在邻接表上.
考虑 add\operatorname{add}add,由于区间可能部分冻结,故乘的长度不是 (r−l+1)(r-l+1)(r−l+1) 而是未封锁元素个数,需要维护.
考虑 mul\operatorname{mul}mul,同样由于区间可能部分冻结,不能直接 ×v\times v×v,而是将未冻结部分 ×v\times v×v,所以需要分开维护未冻结部分和冻结部分的和.
考虑多个冻结操作重叠,由于合并它们很麻烦,所以直接叠加,等到完全解冻才继续 pushdown,所以维护的是冻结次数而不是是否冻结。
写的时候注意细节,具体可以看代码。
Code
7.96KB,1.06s,19.16MB (in total, C++20 with O2)7.96\text{KB},1.06\text{s},19.16\text{MB}\;\texttt{(in total, C++20 with O2)}7.96KB,1.06s,19.16MB(in total, C++20 with O2)
// Problem: P7497 四方喝彩
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P7497
// Memory Limit: 512 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
using ui128 = unsigned __int128;
using f4 = float;
using f8 = double;
using f16 = long double;
template<class T>
bool chmax(T &a, const T &b){
if(a < b){ a = b; return true; }
return false;
}
template<class T>
bool chmin(T &a, const T &b){
if(a > b){ a = b; return true; }
return false;
}
template <int MOD>
struct modint {
int val;
static int norm(const int& x) { return x < 0 ? x + MOD : x; }
modint inv() const {
int a = val, b = MOD, u = 1, v = 0, t;
while (b > 0) t = a / b, swap(a -= t * b, b), swap(u -= t * v, v);
return modint(u);
}
modint() : val(0) {}
modint(const int& m) : val(norm(m % MOD)) {}
modint(const long long& m) : val(norm(m % MOD)) {}
modint operator-() const { return modint(norm(-val)); }
bool operator==(const modint& o) { return val == o.val; }
bool operator!=(const modint &o) { return val != o.val; }
bool operator<(const modint& o) { return val < o.val; }
bool operator>(const modint& o) { return val > o.val; }
bool operator<=(const modint& o) { return val <= o.val; }
bool operator>=(const modint& o) { return val >= o.val; }
modint& operator++() { return *this += 1; }
modint operator++(int) { modint temp = *this; ++(*this); return temp; }
modint& operator--() { return *this -= 1; }
modint operator--(int) { modint temp = *this; --(*this); return temp; }
modint& operator+=(const modint& o) { return val = (1ll * val + o.val) % MOD, *this; }
modint& operator-=(const modint& o) { return val = norm(1ll * val - o.val), *this; }
modint& operator*=(const modint& o) { return val = static_cast<int>(1ll * val * o.val % MOD), *this; }
modint& operator/=(const modint& o) { return *this *= o.inv(); }
modint& operator^=(const modint& o) { return val ^= o.val, *this; }
modint& operator>>=(const modint& o) { return val >>= o.val, *this; }
modint& operator<<=(const modint& o) { return val <<= o.val, *this; }
modint operator-(const modint& o) const { return modint(*this) -= o; }
modint operator+(const modint& o) const { return modint(*this) += o; }
modint operator*(const modint& o) const { return modint(*this) *= o; }
modint operator/(const modint& o) const { return modint(*this) /= o; }
modint operator^(const modint& o) const { return modint(*this) ^= o; }
modint operator>>(const modint& o) const { return modint(*this) >>= o; }
modint operator<<(const modint& o) const { return modint(*this) <<= o; }
friend std::istream& operator>>(std::istream& is, modint& a) {
long long v;
return is >> v, a.val = norm(v % MOD), is;
}
friend std::ostream& operator<<(std::ostream& os, const modint& a) { return os << a.val; }
friend std::string tostring(const modint& a) { return std::to_string(a.val); }
template <class T>
friend modint qpow(const modint& a, const T& b) {
modint x = a, res = 1;
for (T p = b; p; x *= x, p >>= 1)
if (p & 1) res *= x;
return res;
}
};
using Z = modint<1000000007>;
namespace seg_tree {
struct Node {
int l, r, size, blocks;
Z sum_a, sum_b, add, mul;
};
inline int ls(int u) { return u * 2 + 1; }
inline int rs(int u) { return u * 2 + 2; }
struct SegTree {
vector<Node> tr;
inline SegTree() {}
inline SegTree(const vector<int>& a) {
const int n = a.size();
tr.resize(n << 1);
build(0, 0, n - 1, a);
}
inline void pushup(int u, int mid) {
if (tr[u].blocks == 0) {
tr[u].sum_a = tr[ls(mid)].sum_a + tr[rs(mid)].sum_a;
tr[u].sum_b = tr[ls(mid)].sum_b + tr[rs(mid)].sum_b;
tr[u].size = tr[ls(mid)].size + tr[rs(mid)].size;
}
}
inline void apply(const Node& rt, Node& son) {
if (son.blocks == 0) {
son.sum_a = son.sum_a * rt.mul + rt.add * son.size;
son.add = son.add * rt.mul + rt.add;
son.mul *= rt.mul;
}
}
inline void pushdown(int u, int mid) {
apply(tr[u], tr[ls(mid)]);
apply(tr[u], tr[rs(mid)]);
tr[u].add = 0;
tr[u].mul = 1;
}
void build(int u, int l, int r, const vector<int>& a) {
tr[u].l = l;
tr[u].r = r;
tr[u].mul = 1;
tr[u].add = 0;
if (l == r) {
tr[u].sum_a = a[l];
tr[u].size = 1;
return;
}
const int mid = (l + r) >> 1;
build(ls(mid), l, mid, a);
build(rs(mid), mid + 1, r, a);
pushup(u, mid);
}
void add(int u, int l, int r, const Z& val) {
if (tr[u].blocks > 0) return;
if (l <= tr[u].l && tr[u].r <= r) {
tr[u].sum_a += val * tr[u].size;
tr[u].add += val;
return;
}
const int mid = (tr[u].l + tr[u].r) >> 1;
pushdown(u, mid);
if (l <= mid) add(ls(mid), l, r, val);
if (r > mid) add(rs(mid), l, r, val);
pushup(u, mid);
}
void mul(int u, int l, int r, const Z& val) {
if (tr[u].blocks > 0) return;
if (l <= tr[u].l && tr[u].r <= r) {
tr[u].sum_a *= val;
tr[u].add *= val;
tr[u].mul *= val;
return;
}
const int mid = (tr[u].l + tr[u].r) >> 1;
pushdown(u, mid);
if (l <= mid) mul(ls(mid), l, r, val);
if (r > mid) mul(rs(mid), l, r, val);
pushup(u, mid);
}
void block(int u, int l, int r) {
const int mid = (tr[u].l + tr[u].r) >> 1;
if (l <= tr[u].l && tr[u].r <= r) {
if (tr[u].l < tr[u].r) pushdown(u, mid);
if (tr[u].blocks == 0) {
tr[u].sum_b += tr[u].sum_a;
tr[u].sum_a = 0;
tr[u].size = 0;
}
tr[u].blocks++;
return;
}
pushdown(u, mid);
if (l <= mid) block(ls(mid), l, r);
if (r > mid) block(rs(mid), l, r);
pushup(u, mid);
}
void unblock(int u, int l, int r) {
const int mid = (tr[u].l + tr[u].r) >> 1;
if (l <= tr[u].l && tr[u].r <= r) {
tr[u].blocks--;
if (tr[u].blocks == 0) {
if (tr[u].l == tr[u].r) {
tr[u].sum_a += tr[u].sum_b;
tr[u].sum_b = 0;
tr[u].size = 1;
}
else pushup(u, mid);
}
return;
}
pushdown(u, mid);
if (l <= mid) unblock(ls(mid), l, r);
if (r > mid) unblock(rs(mid), l, r);
pushup(u, mid);
}
Z query(int u, int l, int r) {
if (l <= tr[u].l && tr[u].r <= r) return tr[u].sum_a + tr[u].sum_b;
const int mid = (tr[u].l + tr[u].r) >> 1;
Z ans = 0;
pushdown(u, mid);
if (l <= mid) ans += query(ls(mid), l, r);
if (r > mid) ans += query(rs(mid), l, r);
return ans;
}
inline void range_add(int l, int r, const Z& v) { add(0, l, r, v); }
inline void range_mul(int l, int r, const Z& v) { mul(0, l, r, v); }
inline void range_block(int l, int r) { block(0, l, r); }
inline void range_unblock(int l, int r) { unblock(0, l, r); }
inline Z range_sum(int l, int r) { return query(0, l, r); }
};
}
using seg_tree::SegTree;
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int n, m;
scanf("%d%d", &n, &m);
vector<int> a(n);
for (int i = 0; i < n; i++) scanf("%d", &a[i]);
vector<vector<pair<int, int>>> blocks(m);
SegTree sgt(a);
for (int i = 0, op, l, r, v; i < m; i++) {
scanf("%d%d%d", &op, &l, &r), l--, r--;
if (op == 1) {
scanf("%d", &v);
sgt.range_add(l, r, Z(v));
}
if (op == 2) {
scanf("%d", &v);
sgt.range_mul(l, r, Z(v));
}
if (op == 3) {
scanf("%d", &v);
sgt.range_block(l, r);
blocks[i + v].emplace_back(l, r);
}
if (op == 4) printf("%d\n", sgt.range_sum(l, r).val);
for (auto [L, R] : blocks[i]) sgt.range_unblock(L, R);
}
return 0;
}
1103

被折叠的 条评论
为什么被折叠?



