虽然有点难,但是这套题都挂了一个月了啊喂……
网上模板好多……最后还是抄了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
", query(x, y));
} else {
scanf("%d", &z);
Add(x, y, z);
}
}
}
return 0;
}