structBIT { vector<int> t; int N; BIT(int n) { N = n + 1; t.resize(N); } voidupdate(int p, int x){ while (p < N) t[p] += x, p += p & -p; } intquery(int p){ int res = 0; while (p >= 1) res += t[p], p -= p & -p; return res; } intquery(int l, int r){ returnquery(r) - query(l - 1); } };
constexprint N = 5e5 + 8; structBIT { ll t[N]; voidmodify(int p, int x){ while (p < N) t[p] += x, p += p & -p; } ll query(int p){ ll res = 0; while (p >= 1) res += t[p], p -= p & -p; return res; } ll query(int l, int r){ returnquery(r) - query(l - 1); } } bit;
int a[N]; pair<int, int> b[N];
intmain(){ int n = read(); for (int i = 1; i <= n; ++i) b[i] = { read(),i }; sort(b + 1, b + n + 1); for (int i = 1; i <= n; ++i) a[b[i].second] = i; // 离散化
ll sum = 0; bit.init(); for (int i = n; i >= 1; --i) { sum += bit.query(a[i]); // 插入前统计 bit.modify(a[i], 1); // 倒着插入 } printf("%lld\n", sum);
return0; }
注 更标准的离散化写法,即复制、排序、去重、查找,时间复杂度Θ(nlogn):
1 2 3 4 5 6 7 8
int arr[N], val[N]; voideachT(){ memcpy(val, arr, sizeof arr); // 复制 sort(val, val + n); // 排序 int val_size = unique(val, val + n) - val; // 去重 for (int i = 0; i < n; ++i) // 查找 arr[i] = lower_bound(val, val + val_size, arr[i]) - val + 1; }
// 建树 voidbuild(int& self, const vector<info>& a){ if (!p) p = ++pcnt, init(p); if (leaf) return t[p].apply(a[L]); build(lson, a); build(rson, a); returnpush_up(p); } voidbuild(const vector<info>& a){ returnbuild(curr, a); }
// 单点修改 voidmodify(int& self, int x, const info& d){ if (!p) p = ++pcnt, init(p); if (leaf) return t[p].apply(d); if (x < mid) modify(lson, x, d); elsemodify(rson, x, d); returnpush_up(p); } voidmodify(int x, const info& d){ returnmodify(curr, x, d); }
// 查询[l,r) info query(int& self, int l, int r){ if (l <= L && R <= r) return t[p]; info res; if (l < mid) res = res + query(lson, l, r); if (mid < r) res = res + query(rson, l, r); return res; } info query(int l, int r){ if (l >= r) returninfo(); returnquery(curr, l, r); } };
// 建树 voidbuild(int& self, const vector<info>& a){ if (!p) p = ++pcnt, init(p); if (leaf) return t[p].apply(a[L]); build(lson, a); build(rson, a); returnpush_up(p); } voidbuild(const vector<info>& a){ returnbuild(curr, a); }
// 区间[l,r) 修改 voidmodify(int& self, int l, int r, const mark& d){ if (!p) p = ++pcnt, init(p); if (l <= L && R <= r) returnpush_down(curr, d); push_down(curr); if (l < mid) modify(lson, l, r, d); if (mid < r) modify(rson, l, r, d); returnpush_up(p); } voidmodify(int l, int r, const mark& d){ if (l >= r) return; returnmodify(curr, l, r, d); }
// 单点修改 voidmodify(int& self, int x, const info& d){ if (!p) p = ++pcnt, init(p); if (leaf) return t[p].apply(d); push_down(curr); if (x < mid) modify(lson, x, d); elsemodify(rson, x, d); returnpush_up(p); } voidmodify(int x, const info& d){ returnmodify(curr, x, d); }
// 查询[l,r) info query(int& self, int l, int r){ if (l <= L && R <= r) return t[p]; push_down(curr); info res; if (l < mid) res = res + query(lson, l, r); if (mid < r) res = res + query(rson, l, r); return res; } info query(int l, int r){ if (l >= r) returninfo(); returnquery(curr, l, r); }
// 全局找满足 f 的最小下标 intfindL(int& self, auto&& f){ if (!f(t[p])) return inf; // 整个区间不合题意 if (leaf) return L; // 到达叶子 返回键 push_down(curr); int s = findL(lson, f); // 优先看左边 if (s != inf) return s; // 左边合题意 returnfindL(rson, f); // 左边不合题意再看右边 } intfindL(auto&& f){ returnfindL(curr, f); }
// 全局找满足 f 的最大下标 intfindR(int& self, auto&& f){ if (!f(t[p])) return -inf; // 整个区间不合题意 if (leaf) return L; // 到达叶子 返回键 push_down(curr); int s = findR(rson, f); // 优先看右边 if (s != -inf) return s; // 右边合题意 returnfindR(lson, f); // 右边不合题意再看左边 } intfindR(auto&& f){ returnfindR(curr, f); }
// 在区间[l,r) 中找满足 f 的最小下标 intfindL(int& self, int l, int r, auto&& f){ if (l <= L && R <= r && !f(t[p])) return inf; // 在当前区间内且不合题意 if (leaf) return L; // 递归到叶 直接返回 push_down(curr); if (l < mid) { int res = findL(lson, l, r, f); // 先向左递归找 if (res != inf) return res; // 左边不是 -1 说明左边有解 那不用管右边了 } if (mid < r) returnfindL(rson, l, r, f); // 左边无解再看右边 return inf; } intfindL(int l, int r, auto&& f){ returnfindL(curr, l, r, f); }
// 在区间[l,r) 中找满足 f 的最大下标 intfindR(int& self, int l, int r, auto&& f){ if (l <= L && R <= r && !f(t[p])) return -inf; // 在当前区间内且不合题意 if (leaf) return L; // 递归到叶 直接返回 push_down(curr); if (mid < r) { int res = findR(rson, l, r, f); // 先向右递归找 if (res != -inf) return res; // 右边不是 -1 说明右边有解 那不用管左边了 } if (l < mid) returnfindR(lson, l, r, f); // 右边无解再看左边 return -inf; } intfindR(int l, int r, auto&& f){ returnfindR(curr, l, r, f); } };
constexprint N = 5e4 + 8, M = 21; using Z = ModInt<19940417>; Z C[N][M]; voidbeforeT(){ for (int i = 0; i < N; ++i) { C[i][0] = 1; if (i < M) C[i][i] = 1; for (int j = 1; j < i && j < M; ++j) C[i][j] = C[i - 1][j - 1] + C[i - 1][j]; } }
structmark { Z mul{ 1 }; // 乘法标记 Z add{ 0 }; // 加法标记 voidapply(const mark& o, int s)& { mul *= o.mul; add = add * o.mul + o.add; } };
structinfo { vector<Z> sum; info(Z a0 = 0, Z a1 = 0) { sum.resize(M); sum[0] = a0; sum[1] = a1; } voidapply(const mark& o, int s)& { if (o.mul == -1) { for (int i = M - 1; i >= 0; --i) { if (i & 1) sum[i] *= o.mul; } } if (o.add.vale()) { for (int i = M - 1; i >= 0; --i) { for (int j = 1; j <= i; ++j) { if (s - i + j >= 0) sum[i] += C[s - i + j][j] * ((o.add).pow(j)) * sum[i - j]; } } } } voidapply(const info& o)& { *this = o; } friend info operator + (const info& l, const info& r) { info res; for (int i = 0; i < M; ++i) { res.sum[i] = 0; for (int j = 0; j <= i; ++j) { res.sum[i] += l.sum[j] * r.sum[i - j]; } } return res; } };
voideachT(){ int n = read(), q = read();
beforeT(); SMT<info, mark> smt; smt.init(1, n);
for (int i = 1; i <= n; ++i) { int x = read(); smt.modify(i, info{ 1, x }); }
while (q--) { char op = getchar(); int l = read(), r = read(); if (op == 'I') smt.modify(l, r, { 1, read() }); if (op == 'R') smt.modify(l, r, { -1, 0 }); if (op == 'Q') cout << smt.query(l, r).sum[read()] << '\n'; } }
structmark { int asn{ -1 }; // 赋值标记 voidapply(const mark& o, int s)& { if (~o.asn) asn = o.asn; } };
structinfo { int sum{ 0 }; voidapply(const mark& o, int s)& { if (~o.asn) sum = o.asn * s; } voidapply(const info& o)& { *this = o; } friend info operator + (const info& l, const info& r) { return { l.sum + r.sum }; } };
voideachT(){ int n = read(); SMT<info, mark> smt; smt.init(1, n); smt.modify(1, n, { 1 }); for (int q = read(); q--;) { int l = read(), r = read(), op = read(); smt.modify(l, r, { op - 1 }); printf("%d\n", smt.query(1, n).sum); } }
structmark { int asn{ -1 }; voidapply(const mark& o, int s)& { if (~o.asn) asn = o.asn; } };
structinfo { int mx{ 0 }; voidapply(const mark& o, int s)& { if (~o.asn) mx = o.asn; } voidapply(const info& o, int s)& { *this = o; }; friend info operator + (const info& l, const info& r) { return { max(l.mx, r.mx) }; } };
SMT<info, mark> smt; voideachT(){ int n = read(); int L = 0, R = 2e6 + 8;
smt.init(L, R);
set<int> s; s.insert(L), s.insert(R); int lst = L, now = 0; for (int i = 1; i <= n; ++i) { now = read(); smt.modify(lst, lst, { now - lst - 1 }); s.insert(now); lst = now; }
int q = read(); while (q--) { char c; do c = getchar(); while (c != '-' && c != '?' && c != '+'); int x = read();
if (c == '+') { s.insert(x); auto it = s.find(x); int l = *prev(it), r = *next(it); smt.modify(l, l, { x - l - 1 }); smt.modify(x, x, { r - x - 1 }); } elseif (c == '-') { auto it = s.find(x); int l = *prev(it), r = *next(it); s.erase(x); smt.modify(l, l, { r - l - 1 }); smt.modify(x, x, { 0 }); } else { int res = smt.findL([&](constauto& p) { return p.mx >= x; }); if (res == R + 1) res = *next(s.rbegin()); printf("%d%c", res + 1, " \n"[q == 0]); } } }
voidpush_up(int p){ returnpush_up(t[p], t[ls], t[rs]); } voidpush_down(int p, int l){ if (!t[p].mrk) return; if (!ls) ls = ++pcnt, init(ls); push_down(t[ls], t[p].mrk, l - (l >> 1)); if (!rs) rs = ++pcnt, init(rs); push_down(t[rs], t[p].mrk, l >> 1); t[p].mrk = 0; }
voidbuild(auto& a, int& p = rt, int cl = L, int cr = R){ if (!p) p = ++pcnt, init(p); if (cl == cr) returnpush_down(p, a[cl], 1); build(a, lson), build(a, rson); returnpush_up(p); }
voidmodify(int l, int r, int d, int& p = rt, int cl = L, int cr = R){ if (l <= cl && cr <= r) { if (t[p].mn >= d) return; if (t[p].mx < d) returnpush_down(t[p], d, len); } push_down(p, len); if (l <= mid) modify(l, r, d, lson); if (mid < r) modify(l, r, d, rson); returnpush_up(p); }
// 在区间[l,r] 中找到满足 f 的全部位置 voidfindin(int l, int r, auto&& f, int& p = rt, int cl = L, int cr = R){ if (l <= cl && cr <= r && !f(t[p])) return; // 在当前区间内且不合题意 push_down(p, len); if (l <= mid) findin(l, r, f, lson); if (mid < r) findin(l, r, f, rson); returnpush_up(p); } }; int SMT::L, SMT::R, SMT::rt; SMT smt;
voideachT(){ int n = read(), m = read();
smt.init(1, n);
vector<int> arr(n + 1); for (int i = 1; i <= n; ++i) { arr[i] = read(); } smt.build(arr);
while (m--) { int op = read(), x = read(), y = read(); if (op == 1) { smt.modify(1, x, y); } else { int res = 0; smt.findin(x, n, [&](constauto& p) { if (y < p.mn) return0; // 一个都买不起 if (y >= p.sum) { y -= p.sum, res += p.len; // 全买了 买了 cr-cl+1 个,花费 t[p].sum return0; } return1; // 买部分 继续递归 }); printf("%d\n", res); } } }
auto modify = [&](int val, int d) { if (val < 0) sum += val * d; if (val > 0) smt.modify(val, val + 1, { d }); };
vector<int> a(n); for (int i = 0; i < n; ++i) { cin >> a[i]; modify(a[i], 1); }
while (q--) { int p, val; cin >> p >> val; p--;
modify(a[p], -1); a[p] = val; modify(a[p], 1);
ll need = -sum; p = smt.findL([&](const info& p) { if (p.sum <= need) { need -= p.sum; returnfalse; } returntrue; });
int res = 1; res += smt.query(0, p).cnt; res += min(smt.query(p, p + 1).cnt, int(need / p)); // WA: need - smt.query(0, p).sum 因为在二分中已经减去了 cout << res << '\n'; } }
// 将树上节点 x,y 合并到节点 z intmerge(int x, int y, int cl = L, int cr = R){ if (!x || !y) return x | y; // 一方为空 递归到叶 返回非空的那个节点 int z = ++pcnt; if (cl == cr) return/* 合并叶子节点 x,y 将 y 的信息传递给 x */, z; push_down(x), push_down(y); tr[z].ls = merge(tr[x].ls, tr[y].ls, cl, mid); // x 的左节点和 y 的左节点合并为 z 的左节点 tr[z].rs = merge(tr[x].rs, tr[y].rs, mid + 1, cr); // x 的右节点和 y 的右节点合并为 z 的右节点 push_up(z); // 更新当前节点信息 return z; }
voideachT(){ L = 1, R = n, pcnt = 0; for (int i = 1; i <= n; ++i) { rt[i] = ++pcnt; // 建立根节点 modify(num, 1, rt[i]); // 将 num 插入权值线段树 i 指定树的根是 rt[i] } // 建 n 颗权值线段树 for (int q = read(); q--;) { rt[x] = rt[y] = merge(rt[x], rt[y]); // 从树根开始合并 x,y 并将 x 和 y 的根设置为新根 } }
// 将树上节点 x,y 合并到节点 x intmerge(int x, int y, int cl = L, int cr = R){ if (!x || !y) return x | y; // 一方为空 递归到叶 返回非空的那个节点 if (cl == cr) return/* 合并叶子节点 x,y 将 y 的信息传递给 x */, x; push_down(x), push_down(y); tr[x].ls = merge(tr[x].ls, tr[y].ls, cl, mid); // x 的左节点和 y 的左节点合并为 x 的左节点 tr[x].rs = merge(tr[x].rs, tr[y].rs, mid + 1, cr); // x 的右节点和 y 的右节点合并为 x 的右节点 push_up(x); // 更新当前节点信息 return x; }
intfind(int x){ while (x != p[x]) x = p[x] = p[p[x]]; // 路径压缩 return p[x]; }
boolsame(int x, int y){ returnfind(x) == find(y); }
booluno(int x, int y){ x = find(x), y = find(y); if (same(x, y)) returnfalse; siz[x] += siz[y]; p[y] = x; returntrue; }
intsize(int x){ return siz[find(x)]; } };
int rt[N]; voideachT(){ int q = read(), n = 0;
DSU dsu(q);
int L = 1, R = 1e9; smt.init(L, R);
while (q--) { int op = read(); if (op == 1) { // 新建 int a = read(); smt.modify(a, 1, rt[++n]); // 将 1 个 a 插入新节点的权值线段树 } elseif (op == 2) { // 连接 int a = dsu.find(read()), b = dsu.find(read()); if (a == b) continue; // 不能合并自己 rt[a] = rt[b] = smt.merge(rt[a], rt[b]); dsu.uno(a, b); } elseif (op == 3) { // 把小于 b 的变成 b int a = dsu.find(read()), b = read(); int num = smt.query(L, b, rt[a]).siz; // 需要删除 L~b 所有的数 共 num 个 smt.clear(L, b, rt[a]); // 删除 L~b smt.modify(b, num, rt[a]); // 将 num 个 b 插入权值线段树 n } elseif (op == 4) { // 把大于 b 的变成 b int a = dsu.find(read()), b = read(); int num = smt.query(b, R, rt[a]).siz; smt.clear(b, R, rt[a]); smt.modify(b, num, rt[a]); } elseif (op == 5) { // 求 a 的第 b 小 int a = dsu.find(read()), b = read(); printf("%d\n", smt.kthnum(b, rt[a])); } elseif (op == 6) { // 比较 a 和 b 的乘积的大小 int a = dsu.find(read()), b = dsu.find(read()); printf("%d\n", smt.query(L, R, rt[a]).mul > smt.query(L, R, rt[b]).mul); } elseif (op == 7) { // 求 a 的 siz int a = dsu.find(read()); printf("%d\n", smt.query(L, R, rt[a]).siz); } } }
voidinit(int l, int r){ pcnt = 0, rt = 0; L = l, R = r; }
voidinit(int p){ t[p] = { 0, 0, 0 }; }
#define ls t[p].l #define rs t[p].r #define mid ((cl+cr)>>1) #define len (cr-cl+1) #define lson ls,cl,mid #define rson rs,mid+1,cr
// 在这两个函数中写需要维护的东西 voidpush_up(info& p, info l, info r){ p.mx = max(l.mx, r.mx); } voidpush_down(info& p, ll d, int l){ p.mx += d; p.mrk += d; }
// 下传与回溯 voidpush_up(int& p){ push_up(t[p], t[ls], t[rs]); } voidpush_down(int p, int l){ if (l <= 1) return; if (!ls) ls = ++pcnt, init(ls); push_down(t[ls], t[p].mrk, l - (l >> 1)); if (!rs) rs = ++pcnt, init(rs); push_down(t[rs], t[p].mrk, l >> 1); t[p].mrk = 0; }
// 区间[l,r] 加 d voidmodify(int l, int r, ll d, int& p = rt, int cl = L, int cr = R){ if (!p) p = ++pcnt, init(p); if (l <= cl && cr <= r) returnpush_down(t[p], d, len); push_down(p, len); if (l <= mid) modify(l, r, d, lson); if (mid < r) modify(l, r, d, rson); returnpush_up(p); }
// 查询[l,r] info query(int l, int r, int& p = rt, int cl = L, int cr = R){ if (l <= cl && cr <= r) return t[p]; if (r <= mid) returnquery(l, r, lson); if (mid < l) returnquery(l, r, rson); info res; push_up(res, query(l, r, lson), query(l, r, rson)); return res; }
}; int SMT::L, SMT::R, SMT::rt; SMT smt;
/// ---------------- 主函数 ---------------- voideachT(){ int n = read(), W = read(), H = read();
smt.init(-1e9, 1e9);
for (int i = 0; i < n; ++i) { int x = read(), y = read(), d = read(); add(x, x + W - 1, y, y + H - 1, d); } sort(rect.begin(), rect.end()); sort(yall.begin(), yall.end());
voidinit(int l, int r){ pcnt = 0, rt = 0; L = l, R = r; }
voidinit(int p){ t[p] = { 0, 0, 0, 0 }; }
#define ls t[p].l #define rs t[p].r #define mid ((cl+cr)>>1) #define len (cr-cl+1) #define lson ls,cl,mid #define rson rs,mid+1,cr
voidpush_up(int p, int cl, int cr){ if (t[p].mrk) t[p].typ = yall[cr + 1] - yall[cl]; // 标记永久化 yall 是离散化后的数组 else t[p].typ = t[ls].typ + t[rs].typ; }
voidmodify(int l, int r, int d, int& p = rt, int cl = L, int cr = R){ if (!p) p = ++pcnt; if (l <= cl && cr <= r) return t[p].mrk += d, push_up(p, cl, cr); if (l <= mid) modify(l, r, d, lson); if (mid < r) modify(l, r, d, rson); returnpush_up(p, cl, cr); }
ll query(int l = L, int r = R, int& p = rt, int cl = L, int cr = R){ if (l <= cl && cr <= r) return t[p].typ; if (r <= mid) returnquery(l, r, lson); if (mid < l) returnquery(l, r, rson); returnquery(l, r, lson) + query(l, r, rson); } }; int SMT::L, SMT::R, SMT::rt; SMT smt;
voideachT(){ int k = read(), n = read();
smt.init(0, 2 * n);
ll x = 0, y = 0; for (int i = 0; i < n; ++i) { char op; do op = getchar(); while (op != 'N' && op != 'S' && op != 'E' && op != 'W'); int d = read();
if (op == 'N') add(x, x + k, y, y + k + d), y += d; if (op == 'S') add(x, x + k, y - d, y + k), y -= d; if (op == 'E') add(x, x + k + d, y, y + k), x += d; if (op == 'W') add(x - d, x + k, y, y + k), x -= d; } sort(rect.begin(), rect.end()); sort(yall.begin(), yall.end());
vector<int> arr(n + 1); vector<int> alls; for (int i = 1; i <= n; ++i) { arr[i] = read(); alls.push_back(arr[i]); } sort(alls.begin(), alls.end()); alls.erase(unique(alls.begin(), alls.end()), alls.end()); for (int i = 1; i <= n; ++i) { arr[i] = lower_bound(alls.begin(), alls.end(), arr[i]) - alls.begin(); }
staticint B = sqrt(n); structQUE { int ql, qr, id; booloperator<(const QUE& b) const { return ql / B != b.ql / B ? ql < b.ql : (ql / B & 1 ? qr < b.qr : qr > b.qr); } };
int q = read(); vector<QUE> que(q); for (int i = 0; i < q; ++i) { que[i].ql = read(), que[i].qr = read(); que[i].id = i; } sort(que.begin(), que.end());
vector<int> cnt(n); int now = 0; auto add = [&](int p) { if (cnt[arr[p]] == 0) now++; cnt[arr[p]]++; }; auto del = [&](int p) { cnt[arr[p]]--; if (cnt[arr[p]] == 0) now--; };
int cl = 1, cr = 0; vector<int> res(q); for (auto& [ql, qr, id] : que) { while (cl > ql) add(--cl); while (cr < qr) add(++cr); while (cl < ql) del(cl++); while (cr > qr) del(cr--); res[id] = now; }
for (int i = 0; i < q; ++i) { printf("%d\n", res[i]); } }
例 询问区间每种元素出现次数的平方和:
1 2 3 4 5 6 7 8 9 10 11 12
vector<int> cnt(n); int now = 0; auto add = [&](int p) { now -= cnt[arr[p]] * cnt[arr[p]]; cnt[arr[p]]++; now += cnt[arr[p]] * cnt[arr[p]]; }; auto del = [&](int p) { now -= cnt[arr[p]] * cnt[arr[p]]; cnt[arr[p]]--; now += cnt[arr[p]] * cnt[arr[p]]; };
structQUE { int ql, qr, qt, id; booloperator < (const QUE& b) const { return ql / B == b.ql / B ? (qr / B == b.qr / B ? qt < b.qt : qr < b.qr) : ql < b.ql; } } que[N];
structUPD { int pos, c; } upd[N];
int res, arr[N], ans[N]; int cnt[N];
voidadd(int x){ if (cnt[x] == 0) res++; ++cnt[x]; return; }
voiddel(int x){ --cnt[x]; if (cnt[x] == 0) res--; return; }
voidupdate(int x, int qt){ // update() from ct to qt // upd[qt].pos in [ql, qr] if (que[x].ql <= upd[qt].pos && upd[qt].pos <= que[x].qr) { del(arr[upd[qt].pos]); add(upd[qt].c); } std::swap(arr[upd[qt].pos], upd[qt].c); // change the color return; }
voideachT(){ int n = read(), q = read(); B = pow(n, 0.666);
for (int i = 1; i <= n; ++i) { arr[i] = read(); }
int cntq = 0, cntr = 0; for (int i = 1; i <= q; ++i) { std::string op; std::cin >> op;