Splay练手。有点慢。由于Rotate中pushdown(x)和pushdown(y)的顺序搞反了导致答案一直不对。应该是先将父节点的lz标记更新到当前点,再将当前点的lz更新下去再旋转。网上看别人都是用RotateTo函数,从上往下pushdown,所以Rotateh中pushdown顺序就无所谓了。此处节点标号固定,直接用id即可,不必使用RotateTo函数。
再贴一份HH的模板
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
#define N 200005
#define mod 20140518
const int inf = (1 << 29);
typedef long long LL;
int n, m;
int pre[N], key[N], ch[N][2], lz[N], sz[N];
LL sum[N];
//ch[][0]为左孩子,ch[][1]为右孩子
void NewNode(int r, int val){
pre[r] = r - 1;
ch[r - 1][1] = r;
sz[r] = 1;
sum[r] = key[r] = val;
lz[r] = ch[r][0] = ch[r][1] = 0;
}
void pushup(int x){
sum[x] = sum[ch[x][0]] + sum[ch[x][1]] + key[x];
sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1;
}
void pushdown(int x){
if(lz[x]){
key[x] += lz[x];
lz[ch[x][0]] += lz[x];
lz[ch[x][1]] += lz[x];
sum[ch[x][0]] += (LL)lz[x] * sz[ch[x][0]];
sum[ch[x][1]] += (LL)lz[x] * sz[ch[x][1]];
lz[x] = 0;
}
}
//kind = 1为右旋,kind为0左旋
void Rotate(int x,int kind){
int y = pre[x];
pushdown(y);
pushdown(x);
ch[y][!kind] = ch[x][kind];
pre[ch[x][kind]] = y;
if(pre[y]){
ch[pre[y]][ch[pre[y]][1] == y] = x;
}//y节点有父节点用x节点将其替代
pre[x] = pre[y];
ch[x][kind] = y;
pre[y] = x;
pushup(y);
}
void Splay(int r, int goal){
pushdown(r);
while(pre[r] != goal){
int y = pre[r];
int kind = (ch[y][0] == r);
if(pre[y] != goal && (kind == (ch[pre[y]][0] == y))){
Rotate(y, kind);
}
Rotate(r, kind);
}
pushup(r);
}
LL Query(int l, int r){
Splay(l - 1, 0);
Splay(r + 1, l - 1);
return sum[ch[r + 1][0]];
}
void Update(int l, int r, int val){
Splay(l - 1, 0);
Splay(r + 1, l - 1);
lz[ch[r + 1][0]] += val;
sum[ch[r + 1][0]] += (LL) val * sz[ch[r + 1][0]];
}
int main(){
while(scanf("%d%d", &n, &m) != EOF){
ch[0][0] = ch[0][1] = pre[0] = sz[0] = lz[0] = sum[0] = 0;
NewNode(1, 0);
int v;
for(int i = 1; i <= n; i++){
scanf("%d", &v);
NewNode(i + 1, v);
}
NewNode(n + 2, 0);
for(int i = n + 2; i; i--){
pushup(i);
}
char c[10];
int l, r, cc;
for(int i = 0; i < m; i++){
scanf("%s", c);
if(c[0] == 'Q'){
scanf("%d%d", &l, &r);
printf("%I64d\n", Query(l + 1, r + 1));
}
else {
scanf("%d%d%d", &l, &r, &cc);
Update(l + 1, r + 1, cc);
}
}
}
return 0;
}
//模板
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
const int maxn = 100005;
const int INF = (1 << 29);
typedef long long LL;
#define key_value ch[ch[root][1]][0]
using namespace std;
struct SplayTree{
int sz[maxn];
int ch[maxn][2];
int pre[maxn];
int root, top1, top2;
int ss[maxn], que[maxn];
int val[maxn];
inline void Rotate(int x, int f){
int y = pre[x];
pushdown(y);
pushdown(x);
ch[y][!f] = ch[x][f];
pre[ch[x][f]] = y;
if(pre[y])
ch[pre[y]][ch[pre[y]][1] == y ] = x;
pre[x] = pre[y];
ch[x][f] = y;
pre[y] = x;
pushup(y);
}
inline void Splay(int x, int goal){
pushdown(x);
while(pre[x] != goal){
int y = pre[x];
int f = (ch[y][0] == x);
if(pre[y] != goal && (f == ch[pre[y]][0] == y))
Rotate(y, f);
Rotate(x, f);
}
pushup(x);
if(goal == 0)root = x;
}
inline void RotateTo(int k, int goal){
int x = root;
pushdown(x);
while(sz[ch[x][0]] != k){//第一个节点为冗余节点,所以此时x为第k节点
if(k < sz[ch[x][0]])
x = ch[x][0];
else {
k -= (sz[ch[x][0]] + 1);
x = ch[x][1];
}
}
Splay(x, goal);
}
//以上已验证
inline void Erase(int x){
int father = pre[x];
int head = 0, tail = 0;
for(que[tail++] = x; head < tail; head++){
ss[top2++] = que[head];
if(ch[que[head]][0])que[tail++] = ch[que[head]][0];
if(ch[que[head]][1])que[tail++] = ch[que[head]][1];
}
ch[father][ch[father][1] == x] = 0;
pushup(father);
}
//以上一般不修改
inline void debug(){
printf("%d\n", root);
Treaval(root);
}
inline void Treaval(int x){
if(x){
Treaval(ch[x][0]);
printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d ,val = %2d\n",x,ch[x][0],ch[x][1],pre[x],sz[x],val[x]);
Treaval(ch[x][1]);
}
}
//以上debug
//一下是题目特定函数:
int lz[maxn];
LL sum[maxn];
int num[maxn];
inline void NewNode(int &x, int c){
if(top2) x = ss[--top2];//用栈手动压的内存池
else x = ++top1;
ch[x][0] = ch[x][1] = pre[x] = 0;
sz[x] = 1;
val[x] = sum[x] = c;/*题目特定函数*/
lz[x] = 0;
}
inline void pushup(int x){
sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1;
/*题目特定函数*/
sum[x] = sum[ch[x][0]] + sum[ch[x][1]] + val[x];
}
inline void pushdown(int x){/*题目特定函数*/
if(lz[x]){
val[x] += lz[x];
lz[ch[x][0]] += lz[x];
lz[ch[x][1]] += lz[x];
sum[ch[x][0]] += (LL)lz[x] * sz[ch[x][0]];
sum[ch[x][1]] += (LL)lz[x] * sz[ch[x][1]];
lz[x] = 0;
}
}
inline void makeTree(int &x, int l, int r, int f){
if(l > r)return;
int m = (l + r) >> 1;
NewNode(x, num[m]);/*num[m]权值改成题目所需的*/
makeTree(ch[x][0], l, m - 1, x);
makeTree(ch[x][1], m + 1, r, x);
pre[x] = f;
pushup(x);
}
inline void init(int n){
ch[0][0] = ch[0][1] = pre[0] = sz[0] = 0;
lz[0] = sum[0] = 0;
root = top1 = 0;
//增加两个边界顶点
NewNode(root, -1);
NewNode(ch[root][1], -1);
pre[top1] = root;
sz[root] = 2;
for(int i = 0; i < n; i++)
scanf("%d", &num[i]);
makeTree(key_value, 0, n - 1, ch[root][1]);
pushup(ch[root][1]);
pushup(root);
}
inline void Update( ) {/*这是题目特定函数*/
int l , r , c;
scanf("%d%d%d",&l,&r,&c);
RotateTo(l - 1, 0);
RotateTo(r + 1, root);
lz[key_value] += c;
sum[key_value] += (LL)c * sz[key_value];
}
/*询问*/
inline void Query() {/*这是题目特定函数*/
int l , r;
scanf("%d%d",&l,&r);
RotateTo(l - 1 , 0);
RotateTo(r + 1 , root);
printf("%lld\n",sum[key_value]);
}
}spt;
int n, m;
int main(){
while(scanf("%d%d", &n, &m) != EOF){
spt.init(n);
char c[10];
for(int i = 0; i < m; i++){
scanf("%s", c);
if(c[0] == 'Q'){
spt.Query();
}
else {
spt.Update();
}
}
}
return 0;
}