hdu 4348 To the moon 主席树

链接

题意:给你下标从1开始到n的n个数字。有一个时间戳,一开始是0。
有四种操作:
1.C l r d 区间[l,r]中的每个数字都加上d,并且时间戳+1
2.Q l r 询问区间[l,r]的区间和
3.H l r t 询问在时间戳为t的时候[l,r]的区间和
4.B t 把时间戳变为t。

这题可以用主席树来做,时间戳可以用主席树的版本来处理。用root[t]来表示t时刻的信息,然后在root[t]中询问区间和就可以了。由于有区间更新,所以主席树永久标志还是少不了的,否则肯定要超时了。从第4个操作可以发现,时间戳变为t之后,其实时间比t晚的信息都是没有用的,这样的话可以直接把tot更新一下,可以大大节约空间。别的都和普通题目没啥差别。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn=100005;
ll root[maxn],lson[maxn*20],rson[maxn*20],tsize[maxn*20],lazy[maxn*20];
ll num[maxn];
ll tot,cnt;
void build(ll rt,ll l,ll r)
{
    if(l==r)
    {
        tsize[rt]=num[++cnt];
        return;
    }
    ll mid=(l+r)>>1;
    build(lson[rt]=++tot,l,mid);
    build(rson[rt]=++tot,mid+1,r);
    tsize[rt]=tsize[lson[rt]]+tsize[rson[rt]];//向上更新
}

void updata(ll last,ll cur,ll l,ll r,ll x,ll y,ll k)
{
    lson[cur]=lson[last];
    rson[cur]=rson[last];
    lazy[cur]=lazy[last];
    tsize[cur]=tsize[last];
    tsize[cur]+=k*(y-x+1);
    if(l==x&&r==y)
    {
        lazy[cur]+=k;
        return;
    }
    ll mid=(l+r)>>1;
    if(y<=mid)updata(lson[last],lson[cur]=++tot,l,mid,x,y,k);
    else if(x>mid)updata(rson[last],rson[cur]=++tot,mid+1,r,x,y,k);
    else updata(lson[last],lson[cur]=++tot,l,mid,x,mid,k),updata(rson[last],rson[cur]=++tot,mid+1,r,mid+1,y,k);
}

ll query(ll rt,ll l,ll r,ll x,ll y)
{
    if(l==x&&r==y)return tsize[rt];
    ll mid=(l+r)>>1;
    ll tp=lazy[rt]*(y-x+1);//查询的时候不要忘了还要加上延时标记
    if(y<=mid)return query(lson[rt],l,mid,x,y)+tp;
    else if(x>mid)return query(rson[rt],mid+1,r,x,y)+tp;
    else return query(lson[rt],l,mid,x,mid)+query(rson[rt],mid+1,r,mid+1,y)+tp;
}

int main()
{
    ll n,m;
    while(~scanf("%lld%lld",&n,&m))
    {
        for(ll i=1;i<=n;i++)
            scanf("%lld",&num[i]);
        memset(lazy,0,sizeof(lazy));
        memset(tsize,0,sizeof(tsize));
        tot=cnt=0;
        build(root[0]=++tot,1,n);
        char o[2];
        ll x,y,z;
        ll now=0;
        for(ll i=1;i<=m;i++)
        {
            scanf("%s",o);
            if(o[0]=='Q')
            {
                scanf("%lld%lld",&x,&y);
                printf("%lld\n",query(root[now],1,n,x,y));
            }
            else if(o[0]=='C')
            {
                scanf("%lld%lld%lld",&x,&y,&z);
                now++;
                updata(root[now-1],root[now]=++tot,1,n,x,y,z);
            }
            else if(o[0]=='H')
            {
                scanf("%lld%lld%lld",&x,&y,&z);
                printf("%lld\n",query(root[z],1,n,x,y));
            }
            else if(o[0]=='B')
            {
                scanf("%lld",&x);
                if(x<now)tot=root[x+1];//把tot变为x时间戳之后一个的tot
                now=x;                 //题目好像保证新的时间戳比当前的要早,其实不需要if
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_40942372/article/details/82119259
今日推荐