This documentation is automatically generated by online-judge-tools/verification-helper
#include "ds/offline_query/rectangle_add_rectangle_sum.hpp"#include "ds/offline_query/coeffient_query_2d.hpp"
template <typename T, typename XY>
struct Rectangle_Add_Rectangle_Sum {
Coefficient_Query_2D<2, 2, T, XY> CQ;
void add_query(XY x1, XY x2, XY y1, XY y2, T w) {
CQ.add_query(x1, y1, w), CQ.add_query(x1, y2, -w);
CQ.add_query(x2, y1, -w), CQ.add_query(x2, y2, w);
}
void sum_query(XY x1, XY x2, XY y1, XY y2) {
--x1, --y1, --x2, --y2;
CQ.sum_query(x1, y1), CQ.sum_query(x1, y2);
CQ.sum_query(x2, y1), CQ.sum_query(x2, y2);
}
vc<T> calc() {
vc<T> tmp = CQ.calc();
int Q = len(tmp) / 4;
vc<T> res(Q);
FOR(q, Q) {
res[q] = tmp[4 * q] - tmp[4 * q + 1] - tmp[4 * q + 2] + tmp[4 * q + 3];
}
return res;
}
};#line 1 "ds/index_compression.hpp"
template <typename T>
struct Index_Compression_DISTINCT_SMALL {
int mi, ma;
vc<T> dat;
vc<T> build(vc<int> X) {
mi = 0, ma = -1;
if (!X.empty()) mi = MIN(X), ma = MAX(X);
dat.assign(ma - mi + 2, 0);
for (auto& x : X) dat[x - mi + 1]++;
FOR(i, len(dat) - 1) dat[i + 1] += dat[i];
for (auto& x : X) {
x = dat[x - mi]++;
}
FOR_R(i, 1, len(dat)) dat[i] = dat[i - 1];
dat[0] = 0;
return X;
}
int size() { return len(dat); }
int operator()(ll x) { return dat[clamp<ll>(x - mi, 0, ma - mi + 1)]; }
};
template <typename T>
struct Index_Compression_SAME_SMALL {
int mi, ma;
vc<T> dat;
vc<T> build(vc<T> X) {
mi = 0, ma = -1;
if (!X.empty()) mi = MIN(X), ma = MAX(X);
dat.assign(ma - mi + 2, 0);
for (auto& x : X) dat[x - mi + 1] = 1;
FOR(i, len(dat) - 1) dat[i + 1] += dat[i];
for (auto& x : X) {
x = dat[x - mi];
}
return X;
}
int size() { return len(dat); }
int operator()(ll x) { return dat[clamp<ll>(x - mi, 0, ma - mi + 1)]; }
};
template <typename T>
struct Index_Compression_SAME_LARGE {
vc<T> dat;
vc<int> build(vc<T> X) {
vc<int> I = argsort(X);
vc<int> res(len(X));
for (auto& i : I) {
if (!dat.empty() && dat.back() == X[i]) {
res[i] = len(dat) - 1;
} else {
res[i] = len(dat);
dat.eb(X[i]);
}
}
dat.shrink_to_fit();
return res;
}
int size() { return len(dat); }
int operator()(T x) { return LB(dat, x); }
};
template <typename T>
struct Index_Compression_DISTINCT_LARGE {
vc<T> dat;
vc<int> build(vc<T> X) {
vc<int> I = argsort(X);
vc<int> res(len(X));
for (auto& i : I) {
res[i] = len(dat), dat.eb(X[i]);
}
dat.shrink_to_fit();
return res;
}
int size() { return len(dat); }
int operator()(T x) { return LB(dat, x); }
};
template <typename T, bool SMALL>
using Index_Compression_DISTINCT =
typename std::conditional<SMALL, Index_Compression_DISTINCT_SMALL<T>,
Index_Compression_DISTINCT_LARGE<T>>::type;
template <typename T, bool SMALL>
using Index_Compression_SAME =
typename std::conditional<SMALL, Index_Compression_SAME_SMALL<T>,
Index_Compression_SAME_LARGE<T>>::type;
// SAME: [2,3,2] -> [0,1,0]
// DISTINCT: [2,2,3] -> [0,2,1]
// build で列を圧縮してくれる. そのあと
// (x): lower_bound(X,x) をかえす
template <typename T, bool SAME, bool SMALL>
using Index_Compression =
typename std::conditional<SAME, Index_Compression_SAME<T, SMALL>,
Index_Compression_DISTINCT<T, SMALL>>::type;
#line 2 "alg/monoid/add.hpp"
template <typename E>
struct Monoid_Add {
using X = E;
using value_type = X;
static constexpr X op(const X &x, const X &y) noexcept { return x + y; }
static constexpr X inverse(const X &x) noexcept { return -x; }
static constexpr X power(const X &x, ll n) noexcept { return X(n) * x; }
static constexpr X unit() { return X(0); }
static constexpr bool commute = true;
};
#line 3 "ds/fenwicktree/fenwicktree.hpp"
template <typename Monoid>
struct FenwickTree {
using G = Monoid;
using MX = Monoid;
using E = typename G::value_type;
int n;
vector<E> dat;
E total;
FenwickTree() {}
FenwickTree(int n) { build(n); }
template <typename F>
FenwickTree(int n, F f) {
build(n, f);
}
FenwickTree(const vc<E>& v) { build(v); }
void build(int m) {
n = m;
dat.assign(m, G::unit());
total = G::unit();
}
void build(const vc<E>& v) {
build(len(v), [&](int i) -> E { return v[i]; });
}
template <typename F>
void build(int m, F f) {
n = m;
dat.clear();
dat.reserve(n);
total = G::unit();
FOR(i, n) { dat.eb(f(i)); }
for (int i = 1; i <= n; ++i) {
int j = i + (i & -i);
if (j <= n) dat[j - 1] = G::op(dat[i - 1], dat[j - 1]);
}
total = prefix_sum(m);
}
E prod_all() { return total; }
E sum_all() { return total; }
E sum(int k) { return prefix_sum(k); }
E prod(int k) { return prefix_prod(k); }
E prefix_sum(int k) { return prefix_prod(k); }
E prefix_prod(int k) {
chmin(k, n);
E ret = G::unit();
for (; k > 0; k -= k & -k) ret = G::op(ret, dat[k - 1]);
return ret;
}
E sum(int L, int R) { return prod(L, R); }
E prod(int L, int R) {
chmax(L, 0), chmin(R, n);
if (L == 0) return prefix_prod(R);
assert(0 <= L && L <= R && R <= n);
E pos = G::unit(), neg = G::unit();
while (L < R) { pos = G::op(pos, dat[R - 1]), R -= R & -R; }
while (R < L) { neg = G::op(neg, dat[L - 1]), L -= L & -L; }
return G::op(pos, G::inverse(neg));
}
vc<E> get_all() {
vc<E> res(n);
FOR(i, n) res[i] = prod(i, i + 1);
return res;
}
void add(int k, E x) { multiply(k, x); }
void multiply(int k, E x) {
static_assert(G::commute);
total = G::op(total, x);
for (++k; k <= n; k += k & -k) dat[k - 1] = G::op(dat[k - 1], x);
}
void set(int k, E x) { add(k, G::op(G::inverse(prod(k, k + 1)), x)); }
template <class F>
int max_right(const F check, int L = 0) {
assert(check(G::unit()));
E s = G::unit();
int i = L;
// 2^k 進むとダメ
int k = [&]() {
while (1) {
if (i % 2 == 1) { s = G::op(s, G::inverse(dat[i - 1])), i -= 1; }
if (i == 0) { return topbit(n) + 1; }
int k = lowbit(i) - 1;
if (i + (1 << k) > n) return k;
E t = G::op(s, dat[i + (1 << k) - 1]);
if (!check(t)) { return k; }
s = G::op(s, G::inverse(dat[i - 1])), i -= i & -i;
}
}();
while (k) {
--k;
if (i + (1 << k) - 1 < len(dat)) {
E t = G::op(s, dat[i + (1 << k) - 1]);
if (check(t)) { i += (1 << k), s = t; }
}
}
return i;
}
// check(i, x)
template <class F>
int max_right_with_index(const F check, int L = 0) {
assert(check(L, G::unit()));
E s = G::unit();
int i = L;
// 2^k 進むとダメ
int k = [&]() {
while (1) {
if (i % 2 == 1) { s = G::op(s, G::inverse(dat[i - 1])), i -= 1; }
if (i == 0) { return topbit(n) + 1; }
int k = lowbit(i) - 1;
if (i + (1 << k) > n) return k;
E t = G::op(s, dat[i + (1 << k) - 1]);
if (!check(i + (1 << k), t)) { return k; }
s = G::op(s, G::inverse(dat[i - 1])), i -= i & -i;
}
}();
while (k) {
--k;
if (i + (1 << k) - 1 < len(dat)) {
E t = G::op(s, dat[i + (1 << k) - 1]);
if (check(i + (1 << k), t)) { i += (1 << k), s = t; }
}
}
return i;
}
template <class F>
int min_left(const F check, int R) {
assert(check(G::unit()));
E s = G::unit();
int i = R;
// false になるところまで戻る
int k = 0;
while (i > 0 && check(s)) {
s = G::op(s, dat[i - 1]);
k = lowbit(i);
i -= i & -i;
}
if (check(s)) {
assert(i == 0);
return 0;
}
// 2^k 進むと ok になる
// false を維持して進む
while (k) {
--k;
E t = G::op(s, G::inverse(dat[i + (1 << k) - 1]));
if (!check(t)) { i += (1 << k), s = t; }
}
return i + 1;
}
int kth(E k, int L = 0) {
return max_right([&k](E x) -> bool { return x <= k; }, L);
}
};
#line 3 "ds/offline_query/coeffient_query_2d.hpp"
// A, B:定数
// Sparse Laurent Polynomial f(x,y) を与える
// [x^py^q] f(x,y)/(1-x)^A(1-y)^B をたくさん求める
// O(AB N logN) 時間
template <int A, int B, typename T, bool STATIC>
struct Coefficient_Query_2D {
struct Mono {
using value_type = array<T, A * B>;
using X = value_type;
static X op(X x, X y) {
FOR(i, A * B) x[i] += y[i];
return x;
}
static constexpr X unit() { return X{}; }
static constexpr bool commute = 1;
};
vc<tuple<ll, ll, T, int>> query;
int nsum = 0;
Coefficient_Query_2D() {}
void add_query(ll x, ll y, T c) {
if (c != T(0)) query.eb(x, y, c, -1);
}
void sum_query(ll p, ll q) { query.eb(p, q, 0, nsum++); }
// オーバーフローなどの状況次第で書き換える
template <int n>
void comb_array(ll x, array<T, n>& S) {
static_assert(n < 4);
if constexpr (n == 1) S = {T(1)};
if constexpr (n == 2) S = {T(1), T(x)};
if constexpr (n == 3) S = {T(1), T(x), T(x * (x - 1) / 2)};
}
template <int n>
void coef_array(ll b, array<T, n>& S) {
static_assert(n < 4);
// [t^x]t^b(1-t)^{-n} を binom(x,k) の線形結合で表す係数
if constexpr (n == 1) S = {T(1)};
if constexpr (n == 2) S = {T(1 - b), T(1)};
if constexpr (n == 3) S = {T((b - 1) * (b - 2) / 2), T(2 - b), T(1)};
}
vc<T> ANS;
bool done = false;
void calc_static(const vc<int>& ADD_I, vc<int>& GET_I) {
if (ADD_I.empty() || GET_I.empty()) return;
Index_Compression<ll, true, false> IY;
{
vc<ll> tmp;
for (int q : ADD_I) {
auto [a, b, w, qid] = query[q];
if (qid == -1) tmp.eb(b);
}
IY.build(tmp);
}
FenwickTree<Mono> bit(len(IY));
array<T, A> CX;
array<T, B> CY;
array<T, A * B> tmp;
int ptr = 0;
for (int q : GET_I) {
auto [a, b, w, qid] = query[q];
while (ptr < len(ADD_I) && (get<0>(query[ADD_I[ptr]])) <= a) {
int q = ADD_I[ptr++];
auto [a, b, w, qid] = query[q];
coef_array<A>(a, CX);
coef_array<B>(b, CY);
FOR(i, A) FOR(j, B) tmp[B * i + j] = CX[i] * CY[j] * w;
bit.add(IY(b), tmp);
}
comb_array<A>(a, CX);
comb_array<B>(b, CY);
// calc query
tmp = bit.prod(IY(b + 1));
T ans = 0;
FOR(i, A) FOR(j, B) ans += tmp[B * i + j] * CX[i] * CY[j];
ANS[qid] += ans;
}
}
vc<T> calc() {
assert(!done);
done = 1;
ANS.assign(nsum, 0);
int Q = len(query);
auto comp = [&](int i, int j) -> bool {
return (get<0>(query[i])) < (get<0>(query[j]));
};
if (STATIC) {
vc<int> ADD, GET;
FOR(i, Q) { (get<3>(query[i]) == -1 ? ADD : GET).eb(i); }
sort(all(ADD), comp);
sort(all(GET), comp);
calc_static(ADD, GET);
return ANS;
}
auto dfs = [&](auto& dfs, int L, int R) -> pair<vc<int>, vc<int>> {
vc<int> ADD, GET;
if (R == L + 1) {
(get<3>(query[L]) == -1 ? ADD : GET).eb(L);
return {ADD, GET};
}
int M = (L + R) / 2;
auto [ADD1, GET1] = dfs(dfs, L, M);
auto [ADD2, GET2] = dfs(dfs, M, R);
calc_static(ADD1, GET2);
ADD.resize(len(ADD1) + len(ADD2));
GET.resize(len(GET1) + len(GET2));
merge(all(ADD1), all(ADD2), ADD.begin(), comp);
merge(all(GET1), all(GET2), GET.begin(), comp);
return {ADD, GET};
};
dfs(dfs, 0, Q);
return ANS;
}
};
#line 2 "ds/offline_query/rectangle_add_rectangle_sum.hpp"
template <typename T, typename XY>
struct Rectangle_Add_Rectangle_Sum {
Coefficient_Query_2D<2, 2, T, XY> CQ;
void add_query(XY x1, XY x2, XY y1, XY y2, T w) {
CQ.add_query(x1, y1, w), CQ.add_query(x1, y2, -w);
CQ.add_query(x2, y1, -w), CQ.add_query(x2, y2, w);
}
void sum_query(XY x1, XY x2, XY y1, XY y2) {
--x1, --y1, --x2, --y2;
CQ.sum_query(x1, y1), CQ.sum_query(x1, y2);
CQ.sum_query(x2, y1), CQ.sum_query(x2, y2);
}
vc<T> calc() {
vc<T> tmp = CQ.calc();
int Q = len(tmp) / 4;
vc<T> res(Q);
FOR(q, Q) {
res[q] = tmp[4 * q] - tmp[4 * q + 1] - tmp[4 * q + 2] + tmp[4 * q + 3];
}
return res;
}
};