题意: 给定一个序列,要求支持区间增减,区间询问。
解法: 典型的各种树的入门练手题。
第一次写Splay,敲了个指针版的,在空节点的问题上蛋疼了许久。
因为Splay对区间的操作方式是处理成开区间,所以需要在头尾各增加一个虚拟节点,否则可能会产生nill指针的各种死循环。
5000MS时限,Splay跑了3907MS,内存7784K,代码长度2681B。。
笔者特意写了一款线段树对比,1875MS,内存4284K,代码长度1435B。。为什么连内存都是完爆Splay。。一定是我写挫了。。。
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <stdlib.h>
#include <time.h>
using namespace std;
typedef __int64 lld;
// Splay
struct Node {
Node *ch[2];
int id;
int size;
lld val;
lld sum;
lld add;
int cmp(int x) const {
if(x == id) return -1;
return x < id ? 0 : 1;
}
};
Node *nill,*root;
void pushup(Node* o) {
o->size = o->ch[0]->size + o->ch[1]->size + 1;
o->sum = o->ch[0]->sum + o->ch[1]->sum + o->val;
}
void pushdown(Node* o) {
for(int d=0; d<2; d++) {
if(o->ch[d] != nill) {
o->ch[d]->val += o->add;
o->ch[d]->sum += o->ch[d]->size * o->add;
o->ch[d]->add += o->add;
}
}
o->add = 0;
}
void init() {
nill = new Node();
nill->ch[0] = nill->ch[1] = nill;
nill->size = 0;
nill->id = 0;
nill->sum = 0;
root = nill;
}
void rotate(Node* &o, int d) {
Node* tt = o;
pushdown(o);
pushdown(o->ch[d^1]);
o = o->ch[d^1];
tt->ch[d^1] = o->ch[d];
o->ch[d] = tt;
pushup(o->ch[d]);
pushup(o);
}
// 将id为k的节点旋至根
void splay(Node* &o, int k) {
if(o == nill) return;
int d = o->cmp(k);
if(d != -1) {
Node* p = o->ch[d];
int d2 = p->cmp(k);
if(d2 != -1) {
splay(p->ch[d2],k);
if(d == d2) rotate(o,d^1); else rotate(o->ch[d],d);
}
rotate(o,d^1);
}
}
void insert(Node* &o, int id, int val) {
if(o == nill) {
o = new Node();
o->ch[0] = o->ch[1] = nill;
o->size = 1; o->id = id; o->val = val;
}
else {
splay(o,id-1);
insert(o->ch[1],id,val);
pushup(o);
}
}
lld query(int l, int r) {
splay(root,l-1);
splay(root->ch[1],r+1);
return root->ch[1]->ch[0]->sum;
}
void Add(int l, int r, lld num) {
splay(root,l-1);
splay(root->ch[1],r+1);
root->ch[1]->ch[0]->val += num;
root->ch[1]->ch[0]->sum += num * root->ch[1]->ch[0]->size;
root->ch[1]->ch[0]->add += num;
}
void build(int n) {
int x;
insert(root,0,0);
for(int i=1; i<=n; i++) {
scanf("%d", &x);
insert(root,i,x);
}
insert(root,n+1,0);
}
int main() {
int n,nq;
scanf("%d%d", &n, &nq);
init();
build(n);
int l,r;
lld x;
char s[2];
while(nq--) {
scanf("%s%d%d", s, &l, &r);
if(s[0] == 'Q') {
printf("%I64d\n", query(l,r));
}
else {
scanf("%I64d", &x);
Add(l,r,x);
}
}
return 0;
}