hdu 4348 可持久化线段树

本文详细介绍了如何使用可持久化数据结构解决历史状态查询问题,包括在线操作、懒惰更新和避免内存泄漏的方法。通过具体代码实现,展示了如何高效地维护历史版本,以及如何在查询时复用已有节点以节省资源。

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

查询历史状态,在线做的话就要用可持久化数据结构,所谓可持久化,意思就是保存所有的历史状态,但是因为每次修改只涉及到logn个节点,所以每次只新建logn个节点。其余节点及可利用历史版本的。

但是这个题目如果用lazy的话,因为每次查询会下放lazy,导致必须新建节点,最后会造成mle。所以用维护两个值来实现最后的结果。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=1e5+9,maxm=2511111;
long long a[maxn];
int lon,root[maxn*5];
struct
{
    long long x,sum;
    int l,r,ls,rs;
}tr[maxm];

int maketree(int l,int r)
{
    int t=++lon;
    tr[t].l=l;
    tr[t].r=r;
    tr[t].x=tr[t].sum=0;
    if(l==r) return t;
    int mid=l+r>>1;
    tr[t].ls=maketree(l,mid);
    tr[t].rs=maketree(mid+1,r);
    return t;
}

void get(int t,int s)
{
    tr[t]=tr[s];
}

int modify(int t,int x,long long tmp)
{
    int now=++lon;
    get(now,t);
    if(tr[now].l==tr[now].r)
    {
        tr[now].sum+=tmp;
        tr[now].x+=(x-1)*tmp;
        return now;
    }
    int mid=tr[t].l+tr[t].r>>1;
    if(x<=mid) tr[now].ls=modify(tr[now].ls,x,tmp);
    else tr[now].rs=modify(tr[now].rs,x,tmp);
    tr[now].sum=tr[tr[now].ls].sum+tr[tr[now].rs].sum;
    tr[now].x=tr[tr[now].ls].x+tr[tr[now].rs].x;
    return now;
}

long long queryx(int t,int l,int r)
{
    if(tr[t].l==l&&tr[t].r==r)
    return tr[t].x;
    int mid=tr[t].l+tr[t].r>>1;
    if(r<=mid) return queryx(tr[t].ls,l,r);
    else if(mid+1<=l) return queryx(tr[t].rs,l,r);
    else
    {
        long long ret=queryx(tr[t].ls,l,mid);
        ret+=queryx(tr[t].rs,mid+1,r);
        return ret;
    }
}

long long querysum(int t,int l,int r)
{
    if(tr[t].l==l&&tr[t].r==r)
    return tr[t].sum;
    int mid=tr[t].l+tr[t].r>>1;
    if(r<=mid) return querysum(tr[t].ls,l,r);
    else if(mid+1<=l) return querysum(tr[t].rs,l,r);
    else
    {
        long long ret=querysum(tr[t].ls,l,mid);
        ret+=querysum(tr[t].rs,mid+1,r);
        return ret;
    }
}

long long query(int t,int x)
{
    if(x<1) return 0;
    long long sum=querysum(t,1,x);
    long long xx=queryx(t,1,x);
    return sum*x-xx;
}

void init()
{
    lon=0;
}

int main()
{
//    freopen("in.txt","r",stdin);
    int n,m;
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%I64d",&a[i]);
            a[i]+=a[i-1];
        }
        init();
        int now=0;
        root[now]=maketree(1,n);

        for(int i=1;i<=m;i++)
        {
            char tmp[5];
            scanf("%s",tmp+1);
            if(tmp[1]=='Q')
            {
                int l,r;
                scanf("%d %d",&l,&r);
                long long rr=query(root[now],r);
                long long ll=query(root[now],l-1);
                long long ans=rr-ll+a[r]-a[l-1];
                printf("%I64d\n",ans);
            }
            else if(tmp[1]=='C')
            {
                int l,r,d;
                scanf("%d %d %d",&l,&r,&d);
                int tmp=now;
                root[++tmp]=modify(root[now],l,d);
                if(r+1<=n)
                root[now+2]=modify(root[tmp],r+1,-d);
                else root[now+2]=root[now+1];
                now+=2;
            }
            else if(tmp[1]=='H')
            {
                int l,r,t;
                scanf("%d %d %d",&l,&r,&t);
                long long rr=query(root[t*2],r);
                long long ll=query(root[t*2],l-1);
                printf("%I64d\n",rr-ll+a[r]-a[l-1]);
            }
            else
            {
                int t;
                scanf("%d",&t);
                now=t*2;
                lon=root[now+1];
            }
        }
//        cout<<lon<<endl;
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值