SOL:也是颗裸的Splay Tree。。。套模版就好了。改改预处理神马的就Ok啦。
/*
* POJ 3468 模版题
*/
# include<cstdio>
# include<algorithm>
using std::swap;
using std::max;
# define LL long long
# define inf 1<<29
# define keytree (chd[chd[root][1]][0])
# define N 222222
int fa[N],chd[N][2],val[N],sz[N],add[N];
LL sum[N];
int root,tot1,tot2;
int q[N],s[N]; //回收内存
int num[N];
/*
* 更新关键字
*/
void PushUp(int x)
{
sz[x]=sz[chd[x][0]]+1+sz[chd[x][1]];
sum[x]=sum[chd[x][0]]+val[x]+sum[chd[x][1]];
}
void update_add(int x,int c)
{
add[x]+=c;
val[x]+=c;
sum[x]+=(LL)(sz[x])*c;
}
/*
* 标记下下放
*/
void PushDown(int x)
{
if(add[x])
{
// val[x]+=add[x];
update_add(chd[x][0],add[x]);
update_add(chd[x][1],add[x]);
add[x]=0;
}
}
/*
* 旋转操作, t=0 表示左旋, t=1 表示右旋
*/
void rotate(int x,int t)
{
int y=fa[x];
PushDown(y);
PushDown(x);
chd[y][!t]=chd[x][t];
fa[chd[x][t]]=y;
fa[x]=fa[y];
if(fa[x])
chd[fa[y]][chd[fa[y]][1]==y]=x;
chd[x][t]=y;
fa[y]=x;
PushUp(y);
}
/*
* 旋转使x成为goal的子节点,若goal为0则x旋转为根节点
*/
void splay(int x,int goal)
{
PushDown(x);
while(fa[x]!=goal)
{
if(fa[fa[x]]==goal)
rotate(x,chd[fa[x]][0]==x);
else
{
int y=fa[x],z=fa[y];
int t=(chd[z][0]==y);
if(chd[y][t]==x)
rotate(x,!t),rotate(x,t);
else
rotate(y,t),rotate(x,t);
}
}
PushUp(x);
if(goal==0)
root=x;
}
/*
* 找到位置为k的节点,返回其值,并将其升至x的儿子
*/
int select(int k,int goal)
{
int x=root;
PushDown(x);
while(sz[chd[x][0]]!=k)
{
if(k<sz[chd[x][0]])
x=chd[x][0];
else
{
k-=(sz[chd[x][0]]+1);
x=chd[x][1];
}
PushDown(x);
}
int kth=val[x];
splay(x,goal);
return kth;
}
/*
* 将以x为根的整棵子树删除掉,并回收内存
*/
void erase(int x)
{
int f=fa[x],head=0,tail=0;
for(q[tail++]=x;head<tail;head++)
{
s[tot2++]=q[head];
if(chd[q[head]][0])
q[tail++]=chd[q[head]][0];
if(chd[q[head]][1])
q[tail++]=chd[q[head]][1];
}
chd[f][chd[f][1]==x]=0;
PushUp(f);
}
/*
* 在x节点处生成一个新的节点,值为x,父节点为f,之前删除的节点会放到s中以便再利用
*/
void newnode(int &x,int v,int f)
{
if(tot2)
x=s[--tot2];
else
x=++tot1;
chd[x][0]=chd[x][1]=0;
fa[x]=f;
sz[x]=1;
sum[x]=val[x]=v; //????????
add[x]=0;
}
/*
* 用num数组中[l,r]区间内的值建树
*/
void build(int &x,int l,int r,int f)
{
if(l<=r)
{
int m=(l+r)>>1;
newnode(x,num[m],f);
build(chd[x][0],l,m-1,x);
build(chd[x][1],m+1,r,x);
PushUp(x);
}
}
void init()
{
chd[0][0]=chd[0][1]=fa[0]=sz[0]=0;
add[0]=sum[0]=0;
root=tot1=tot2=0;
newnode(root,-inf,0);
newnode(chd[root][1],-inf,root);
sz[root]=2;
}
void query(int l,int r)
{
select(l-1,0);
select(r+1,root);
printf("%lld\n",sum[keytree]);
}
void update(int l,int r,int c)
{
select(l-1,0);
select(r+1,root);
update_add(keytree,c);
}
int main()
{
int n,m,i,l,r,c;
char op[10];
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
for(i=1;i<=n;i++)
scanf("%d",&num[i]);
build(keytree,1,n,chd[root][1]);
for(i=1;i<=m;i++)
{
scanf("%s",op);
if(op[0]=='Q')
{
scanf("%d%d",&l,&r);
query(l,r);
}
else
{
scanf("%d%d%d",&l,&r,&c);
update(l,r,c);
}
}
}
return 0;
}
本文详细介绍了一种自平衡二叉查找树——伸展树(SplayTree)的实现原理及应用案例。通过具体实例展示了伸展树在数据结构操作如插入、删除、查找等过程中的高效表现,并提供了完整的代码实现。
426

被折叠的 条评论
为什么被折叠?



