hdu3468 splay

本文介绍了一种利用Splay树来高效处理区间加法及区间和查询的问题。通过实例代码详细解释了Splay树的旋转、下传懒标记等关键操作,并展示了如何构建树形结构以支持快速更新和查询。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:其实就是区间的加法和询问区间的和

解法:主要为了尝试一下splay维护区间和 因为之前只写过splay区间加法维护 

然后觉得很神奇啊 左右两个节点是不算内的,以前写单点都没有发现这一点吧

#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;
#define ls ch[rt][0]
#define rs ch[rt][1]
#define rrs ch[root][1]
#define rls ch[root][0]
#define maxn 222222
int n,m;
int ch[maxn][2],fa[maxn],root,num[maxn],cnt;
ll sum[maxn],add[maxn],a[maxn],val[maxn];
inline void node(int rt){fa[rt]=sum[rt]=add[rt]=ls=rs=0;num[rt]=1;}
inline void up(int rt){
    sum[rt]=val[rt]+sum[ls]+sum[rs];
    num[rt]=num[ls]+num[rs]+1;
}
inline void down(int rt){
    if(add[rt]){
        if(ls)add[ls]+=add[rt],val[ls]+=add[rt],sum[ls]+=add[rt]*(num[ls]);
        if(rs)add[rs]+=add[rt],val[rs]+=add[rt],sum[rs]+=add[rt]*(num[rs]);
        add[rt]=0;
    }
}
inline void rot(int rt){
    int f=fa[rt],side=ch[f][1]==rt,ll=ch[rt][!side];
    fa[ll]=f,ch[f][side]=ll;
    fa[rt]=fa[f],ch[fa[f]][ch[fa[f]][1]==f]=rt;
    fa[f]=rt,ch[rt][!side]=f;
    up(f),up(rt);
}
void splay(int rt,int aim){
    while(fa[rt]!=aim){
        down(rt);
        int f=fa[rt],ff=fa[f];
        if(ff==aim)rot(rt);
        else if((ch[f][1]==rt)==(ch[ff][1]==f))rot(f),rot(rt);
        else rot(rt),rot(rt);
    }if(!aim)root=rt;
}
inline void find(int tot,int sub){
    int rt=sub;
    while(1){
        down(rt);
        if(num[ls]+1==tot)break;
        if(num[ls]>=tot)rt=ls;
        else tot-=num[ls]+1,rt=rs;
    }splay(rt,fa[sub]);
}
void _add(int l,int r,ll w){
    find(l,root);find(r-l+2,rrs);
    int rt=ch[rrs][0];
    sum[rt]+=w*num[rt];add[rt]+=w;val[rt]+=w;
}
void build(int n){
    cnt=0;node(0);num[0]=0;
    node(++cnt);
    for(int i=2;i<=n+1;++i){
        node(++cnt);fa[i-1]=i;ch[i][0]=i-1;val[i]=a[i];up(i);
    }root=cnt;
    node(++cnt);fa[cnt]=cnt-1;ch[cnt-1][1]=cnt;up(root);
//    for(int i=1;i<=n+2;++i)
//        printf("%d %d %d %lld\n",i,fa[i],num[i],sum[i]);
    
}
char op[111];
int l,r;
int main(){
    while(~scanf("%d%d",&n,&m)){
        for(int i=2;i<=n+1;++i)scanf("%lld",&a[i]);
        build(n);
        while(m--){
            scanf("%s%d%d",op,&l,&r);
            if(*op=='Q'){
                find(l,root);find(r-l+2,rrs);
//                printf("%lld %lld\n",val[root],val[rrs]);
                printf("%lld\n",sum[ch[rrs][0]]);
            }else if(*op=='C'){
                ll w;scanf("%lld",&w);
                _add(l,r,w);
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值