牛客-Forsaken的数列(Treap)
题目传送门
sol:第一次看题还真信了是用线段树来做,但是没什么想法,看了题解发现是我不会的Treap,然后花了几天时间学习了一下并补掉题目
- 无旋Treap
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int MAXN = 2e5 + 10; struct Treap { int ls, rs; int rand, size; LL sum, val, lazy; } node[MAXN]; int root, tot; int add_node(int v) { int i = ++tot; node[i].ls = node[i].rs = 0; node[i].rand = rand(); node[i].sum = node[i].val = v; node[i].lazy = 0; node[i].size = 1; return i; } void push_down(int rt) { int ls = node[rt].ls; int rs = node[rt].rs; if (ls != 0) { node[ls].lazy += node[rt].lazy; node[ls].val += node[rt].lazy; node[ls].sum += node[ls].size * node[rt].lazy; } if (rs != 0) { node[rs].lazy += node[rt].lazy; node[rs].val += node[rt].lazy; node[rs].sum += node[rs].size * node[rt].lazy; } node[rt].lazy = 0; } void push_up(int rt) { int ls = node[rt].ls; int rs = node[rt].rs; node[rt].size = node[ls].size + node[rs].size + 1; node[rt].sum = node[ls].sum + node[rs].sum + node[rt].val; } void split(int rt, int& a, int& b, int s) { if (rt == 0) { a = b = 0; return; } push_down(rt); int size = node[node[rt].ls].size; if (size < s) { a = rt; split(node[rt].rs, node[a].rs, b, s - size - 1); } else { b = rt; split(node[rt].ls, a, node[b].ls, s); } push_up(rt); } void merge(int& rt, int a, int b) { if (a == 0 || b == 0) { rt = a + b; return; } push_down(a); push_down(b); if (node[a].rand < node[b].rand) { rt = a; merge(node[rt].rs, node[a].rs, b); } else { rt = b; merge(node[rt].ls, a, node[b].ls); } push_up(rt); } void insert(int p, int v) { int x = 0, y = 0; split(root, x, y, p - 1); merge(root, x, add_node(v)); merge(root, root, y); } void add(int l, int r, int v) { int x = 0, y = 0, z = 0; split(root, root, z, r); split(root, x, y, l - 1); node[y].lazy += v; node[y].val += v; node[y].sum += node[y].size * v; merge(root, x, y); merge(root, root, z); } LL query(int l, int r) { int x = 0, y = 0, z = 0; split(root, root, z, r); split(root, x, y, l - 1); LL sum = node[y].sum; merge(root, x, y); merge(root, root, z); return sum; } int main() { int n, q; scanf("%d", &n); for (int i = 1; i <= n; i++) { int v; scanf("%d", &v); merge(root, root, add_node(v)); } scanf("%d", &q); for (int i = 1; i <= q; i++) { int opt; scanf("%d", &opt); if (opt == 1) { int pos; scanf("%d", &pos); insert(pos, 0); } else if (opt == 2) { int l, r, v; scanf("%d%d%d", &l, &r, &v); add(l, r, v); } else { int l, r; scanf("%d%d", &l, &r); printf("%lld\n", query(l, r)); } } return 0; }
在前置知识都掌握的情况下Treap还是挺好懂的,而且之前感觉lazy标记挺乱的,看了这题之后感觉理清了
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步