Description
给定序列 a=(a1,a2,⋯ ,an)a=(a_1,a_2,\cdots,a_n)a=(a1,a2,⋯,an) 和 b=(b1,b2,⋯ ,bn)b=(b_1,b_2,\cdots,b_n)b=(b1,b2,⋯,bn),有 mmm 个操作分三种:
- add(l,r,k,t)\operatorname{add}(l,r,k,t)add(l,r,k,t):对每个 i∈[l,r]i\in[l,r]i∈[l,r],若 ai×bi≤ka_i\times b_i\le kai×bi≤k,则执行 ai←ai+t,bi←bi+ta_i\gets a_i+t,b_i\gets b_i+tai←ai+t,bi←bi+t.
- set(i,x,y)\operatorname{set}(i,x,y)set(i,x,y):执行 ai←x,bi←ya_i\gets x,b_i\gets yai←x,bi←y.
- query(l,r)\operatorname{query}(l,r)query(l,r):求 ∑i=lrai+bi\sum\limits_{i=l}^r a_i+b_ii=l∑rai+bi.
Limitations
1≤n,m≤1051 \le n,m \le 10^51≤n,m≤105
0≤ai,bi,k,t,x,y≤1050 \le a_i,b_i,k,t,x,y \le 10^50≤ai,bi,k,t,x,y≤105
2s,512MB2\text{s},512\text{MB}2s,512MB
Solution
若没有 add\operatorname{add}add 操作是容易维护的.
对于 add\operatorname{add}add,若 t=0t=0t=0 直接忽略;否则 t>0t>0t>0,易得一个数至多连续进行 k\sqrt kk 次 add\operatorname{add}add.
由于初始的 aaa 和 set\operatorname{set}set 操作至多带来约 (n+q)(n+q)(n+q) 个数,故 add\operatorname{add}add 至多影响 (n+q)k(n+q)\sqrt k(n+q)k 个数.
于是可在线段树上维护 ai×bia_i\times b_iai×bi 的最小值,若 kkk 大于最小值则直接返回,否则递归修改.
时间复杂度 O((n+q)klognO((n+q)\sqrt k\log nO((n+q)klogn).
Code
2.63KB,1.39s,17.27MB (in total, C++20 with O2)2.63\text{KB},1.39\text{s},17.27\text{MB}\;\texttt{(in total, C++20 with O2)}2.63KB,1.39s,17.27MB(in total, C++20 with O2)
#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;
}
inline int ls(int u) { return 2 * u + 1; }
inline int rs(int u) { return 2 * u + 2; }
struct Node {
int l, r;
i64 a, b, sum, min;
void upd(i64 x, i64 y) { a = x, b = y, sum = x + y, min = x * y; }
};
struct SegTree {
vector<Node> tr;
inline SegTree() {}
inline SegTree(const vector<i64>& a, const vector<i64>& b) {
const int n = a.size();
tr.resize(n << 2);
build(0, 0, n - 1, a, b);
}
inline void pushup(int u) {
tr[u].sum = tr[ls(u)].sum + tr[rs(u)].sum;
tr[u].min = min(tr[ls(u)].min, tr[rs(u)].min);
}
inline void build(int u, int l, int r, const vector<i64>& a, const vector<i64>& b) {
tr[u].l = l, tr[u].r = r;
if (l == r) return tr[u].upd(a[l], b[l]);
const int mid = (l + r) >> 1;
build(ls(u), l, mid, a, b);
build(rs(u), mid + 1, r, a, b);
pushup(u);
}
inline void update(int u, int l, int r, i64 k, i64 t) {
if (tr[u].min > k || t == 0) return;
if (tr[u].l == tr[u].r) return tr[u].upd(tr[u].a + t, tr[u].b + t);
const int mid = (tr[u].l + tr[u].r) >> 1;
if (l <= mid) update(ls(u), l, r, k, t);
if (r > mid) update(rs(u), l, r, k, t);
pushup(u);
}
inline void set(int u, int p, i64 s, i64 t) {
if (tr[u].l == tr[u].r) return tr[u].upd(s, t);
const int mid = (tr[u].l + tr[u].r) >> 1;
if (p <= mid) set(ls(u), p, s, t);
else set(rs(u), p, s, t);
pushup(u);
}
inline i64 sum(int u, int l, int r) {
if (l <= tr[u].l && tr[u].r <= r) return tr[u].sum;
const int mid = (tr[u].l + tr[u].r) >> 1;
i64 res = 0;
if (l <= mid) res += sum(ls(u), l, r);
if (r > mid) res += sum(rs(u), l, r);
return res;
}
};
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int n, m;
scanf("%d %d", &n, &m);
vector<i64> a(n), b(n);
for (int i = 0; i < n; i++) scanf("%lld", &a[i]);
for (int i = 0; i < n; i++) scanf("%lld", &b[i]);
SegTree seg(a, b);
for (int i = 0, op; i < m; i++) {
scanf("%d", &op);
if (op == 1) {
int l, r; i64 k, t;
scanf("%d %d %lld %lld", &l, &r, &k, &t), l--, r--;
seg.update(0, l, r, k, t);
}
else if (op == 2) {
int p; i64 s, t;
scanf("%d %lld %lld", &p, &s, &t), p--;
seg.set(0, p, s, t);
}
else {
int l, r;
scanf("%d %d", &l, &r), l--, r--;
printf("%lld\n", seg.sum(0, l, r));
}
}
return 0;
}
963

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



