虽然有点难,但是这套题都挂了一个月了啊喂……
网上模板好多……最后还是抄了kuangbin聚聚的,毕竟好多模板都是抄他的,比较习惯……
POJ 3468
题意:给n个数,两种操作,区间整体加一个数,或者区间求和。
题解:把区间的前一个数挪到根,区间后一个数挪到根的右子树,根的右子树的左子树就是要处理的区间。。。
SplayTree是一个二叉排序树,它所保存的顺序是数字的编号,所以无论怎样旋转,编号的顺序都不会变。。。
在首尾各插入一个结点,这样求整个区间的时候也可以找到前一个数和后一个数。。。
照了别人的博客写了两遍,自己又裸敲一遍,还是错了好多细节,不过大概理解了。。。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int N = 100010; int sz[N], ch[N][2], pre[N]; int a[N]; ll sum[N], add[N], key[N]; int root, tot; void new_node(int &o, int fa, int k) { o = ++tot; sz[o] = 1; ch[o][0] = ch[o][1] = 0; pre[o] = fa; sum[o] = key[o] = k; add[o] = 0; } void push_up(int o) { sum[o] = sum[ch[o][0]] + sum[ch[o][1]] + key[o]; sz[o] = sz[ch[o][0]] + sz[ch[o][1]] + 1; // +1 !! } void update(int o, int v) { if (!o) return ; add[o] += v; key[o] += v; sum[o] += (ll)sz[o]*v; } void push_down(int o) { if (add[o]) { update(ch[o][1], add[o]); update(ch[o][0], add[o]); add[o] = 0; } } void build(int &o, int l, int r, int fa) { if (l > r) return; int mid = (l+r) >> 1; new_node(o, fa, a[mid]); build(ch[o][0], l, mid-1, o); build(ch[o][1], mid+1, r, o); push_up(o); } void init(int n) { root = tot = 0; sz[0] = ch[0][0] = ch[0][1] = pre[0] = 0; sum[0] = add[0] = key[0] = 0; new_node(root, 0, -1); new_node(ch[root][1], root, -1); build(ch[ch[root][1]][0], 1, n, ch[root][1]); push_up(ch[root][1]); push_up(root); } void rotate(int o, int d) { // 0:left 1:right int fa = pre[o]; push_down(fa); push_down(o); ch[fa][!d] = ch[o][d]; pre[ch[o][d]] = fa; if (pre[fa]) ch[pre[fa]][ch[pre[fa]][1]==fa] = o; pre[o] = pre[fa]; ch[o][d] = fa; pre[fa] = o; push_up(fa); } void splay(int o, int goal) { push_down(o); while (pre[o] != goal) { if (pre[pre[o]] == goal) { rotate(o, ch[pre[o]][0] == o); } else { int fa = pre[o]; int d = (ch[pre[fa]][0] == fa); if (ch[fa][d] == o) { rotate(o, !d); rotate(o, d); } else { rotate(fa, d); rotate(o, d); } } } push_up(o); if (goal == 0) root = o; } int get_kth(int o, int k) { push_down(o); //!! int t = sz[ch[o][0]] + 1; if (t == k) return o; if (t > k) return get_kth(ch[o][0], k); return get_kth(ch[o][1], k-t); } ll query(int l, int r) { splay(get_kth(root, l), 0); splay(get_kth(root, r+2), root); return sum[ ch[ch[root][1]][0] ]; } void Add(int l, int r, int v) { splay(get_kth(root, l), 0); splay(get_kth(root, r+2), root); update(ch[ch[root][1]][0], v); push_up(ch[root][1]); push_up(root); } int main() { //freopen("in.txt", "r", stdin); int n, q; while (~scanf("%d%d", &n, &q) && n) { for (int i = 1; i <= n; ++i) scanf("%d", a+i); init(n); char op[2]; int x, y, z; while (q--) { scanf("%s%d%d", op, &x, &y); if (*op == ‘Q‘) { printf("%lld\n", query(x, y)); } else { scanf("%d", &z); Add(x, y, z); } } } return 0; }
时间: 2024-10-24 13:35:58