题目链接:http://poj.org/problem?id=3468
题目描述:给你一个序列,有两个操作,1. 给某个区间[ l, r]的每个元素加 c,2. 查询某个区间的和
解题思路:之前已经用线段树写过这道题了,现在初学splay,再用splay做一遍,其实只需要每个节点多记一个sum就可以了
//#pragma comment(linker,"/STACK:102400000,102400000")
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<string>
#define ll long long
#define db double
#define PB push_back
#define lson k<<1
#define rson k<<1|1
using namespace std;
const int N = 100005;
struct node *null;
struct node
{
node *ch[2];
int v,lz,s;
ll sum;
int cmp(int x)
{
int d=x-ch[0]->s;
if(d==1) return -1;
return d<=0?0:1;
}
void add(node *p,int val)
{
if(p==null) return;
p->lz+=val,p->sum+=(ll)val*(ll)p->s,p->v+=val;
}
void pushdown()
{
if(lz!=0)
{
add(ch[0],lz),add(ch[1],lz);
lz=0;
}
}
void pushup()
{
sum=v+ch[0]->sum+ch[1]->sum;
s=1+ch[0]->s+ch[1]->s;
}
} seq[N],*root;
int a[N];
node* build(int l,int r)
{
if(l>r) return null;
int mid=(l+r)>>1;
node *tmp=build(l,mid-1);
node *p=&seq[mid];
p->lz=0,p->v=a[mid],p->ch[0]=tmp;
p->ch[1]=build(mid+1,r);
p->pushup();
return p;
}
void rotate(node *&o,int d)
{
node *k=o->ch[d^1];o->ch[d^1]=k->ch[d],k->ch[d]=o;
o->pushup();
o=k;
}
void splay(node *&o,int k)
{
int d=o->cmp(k);
o->pushdown();
if(d!=-1)
{
if(d==1) k-=o->ch[0]->s+1;
node *p=o->ch[d];
int d2=p->cmp(k);
if(d2==1) k-=p->ch[0]->s+1;
p->pushdown();
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);
}
o->pushup();
}
int main()
{
#ifdef PKWV
freopen("in.in","r",stdin);
#endif // PKWV
int n,Q;
scanf("%d%d",&n,&Q);
for(int i=1;i<=n;i++) scanf("%d",&a[i+1]);
null=new node();
null->s=0,null->sum=0LL;
root=build(1,n+2);
while(Q--)
{
char ch[10];
int a,b,c;
scanf("%s%d%d",ch,&a,&b);
splay(root,a);
splay(root->ch[1],b-a+2);
node *tmp=root->ch[1]->ch[0];
if(ch[0]=='Q')
{
printf("%I64d\n",tmp->sum);
}else
{
scanf("%d",&c);
tmp->lz+=c;
tmp->v+=c;
tmp->sum+=(ll)c*tmp->s;
}
}
return 0;
}