强基计划 题解
强化基础算法,提升个人水平。
#65. 跳树
考虑建线段树,对每个节点维护 rt, l, num
分别代表最高跳到哪层,跳到最高后最低到哪层,以及往下跳的路径(左儿子右儿子)。
然后合并时注意细节。
代码:
#include <bits/stdc++.h> #define int long long #define rep(i, l, r) for (int i = l; i <= r; i++) #define per(i, l, r) for (int i = l; i >= r; i--) using namespace std; struct d { int rt, l, num; d(int rt = 0, int l = 0, int num = 0):rt(rt), l(l), num(num) {} d operator+(d o) { if (!rt && !l) return o; if (!o.rt && !o.l) return *this; if (l > o.rt) { d ans; ans.rt = rt; ans.l = l - o.rt + o.l; ans.num = ((num >> o.rt) << o.l) + o.num; return ans; } else { d ans; ans.rt = rt + o.rt - l; ans.l = o.l; ans.num = o.num; return ans; } } d operator =(d o) { rt = o.rt; l = o.l; num = o.num; return *this; } }dat[2000010]; int opt[2000010], n, m, q, type, s, l, r, x, y; d create(int opt) { if (opt == 1) return d(0, 1, 0); if (opt == 2) return d(0, 1, 1); if (opt == 3) return d(1, 0, 0); } void build(int p, int l, int r) { // cerr << p << " " << l << " " << r << "\n"; if (l == r) { // cerr << p << "\n"; dat[p] = create(opt[l]); // cerr << p << "\n"; } else { int mid = (l + r) / 2; build(2 * p, l, mid); build(2 * p + 1, mid + 1, r); dat[p] = dat[2 * p] + dat[2 * p + 1]; } } void modify(int p, int l, int r, int k) { if (l == r) { dat[p] = create(opt[l]); } else { int mid = (l + r) / 2; if (k > mid) modify(2 * p + 1, mid + 1, r, k); else modify(2 * p, l, mid, k); dat[p] = dat[2 * p] + dat[2 * p + 1]; } } d query(int p, int cl, int cr, int l, int r) { // cerr << p << " " << cl << " " << cr << " " << l << " " << r << "\n"; if (l >= cl && r <= cr) { return dat[p]; } else if (l > cr || r < cl) { return d(); } else { int mid = (l + r) / 2; return query(2 * p, cl, cr, l, mid) + query(2 * p + 1, cl, cr, mid + 1, r); } } signed main() { // cerr << "here" << "\n"; cin >> n >> m >> q; // cerr << "here" << "\n"; rep (i, 1, m) { cin >> opt[i]; } // cerr << "here" << "\n"; build(1, 1, m); // cerr << "here" << "\n"; rep (i, 1, q) { // cerr << i << "\n"; cin >> type; if (type == 1) { cin >> s >> l >> r; d k = query(1, l, r, 1, m); cout << (max(1ll, s >> k.rt) << k.l) + k.num << "\n"; } else { cin >> x >> y; opt[x] = y; modify(1, 1, m, x); } } }
#66. [NOI Online #1 提高组] 冒泡排序
考虑记录对于一个数,前面比它大的数有几个。
然后一轮冒泡排序中,设对于某一个数,前面比它大的数的个数为
随后离散化后树状数组即可。
代码:
#include <bits/stdc++.h> #define int long long #define rep(i, l, r) for (int i = l; i <= r; i++) using namespace std; int p[200010], v[200010], n, m, opt, c, sum; struct BIT { int tr[200010]; BIT() {} int lowbit(int i) { return i & -i; } void add(int x, int d) { x++; while (x) { tr[x] += d; x -= lowbit(x); } } int query(int x) { x++; int res = 0; while (x <= n) { res += tr[x]; x += lowbit(x); } return res; } int queryPoint(int x) { return query(x) - query(x - 1); } }tr1, tr2, tr3; signed main() { int cnt = 0; cin >> n >> m; rep (i, 1, n) { cin >> p[i]; sum += p[i]; int x = tr3.query(p[i]); v[i] = x; tr2.add(x, v[i]); tr1.add(x, 1); tr3.add(p[i], 1); } rep (i, 1, m) { // cerr << i << "\n"; // rep (j, 1, n) { // cerr << v[j] << " "; // } // cerr << "\n"; cin >> opt >> c; if (opt == 1) { tr2.add(v[c], -v[c]); tr2.add(v[c + 1], -v[c + 1]); tr1.add(v[c], -1); tr1.add(v[c + 1], -1); swap(v[c], v[c + 1]); if (p[c] < p[c + 1]) { v[c + 1]++; } else { v[c]--; } swap(p[c], p[c + 1]); tr2.add(v[c], v[c]); tr2.add(v[c + 1], v[c + 1]); tr1.add(v[c], 1); tr1.add(v[c + 1], 1); } else { int k = c; // k++; if (k >= n - 1) { cout << 0 << endl; } else { cout << tr2.query(k) - tr1.query(k) * k << endl; } } } }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库