hdu 4348 可持续化线段树

                                              To the moon

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2423    Accepted Submission(s): 480


Problem Description
Background
To The Moon is a independent game released in November 2011, it is a role-playing adventure game powered by RPG Maker.
The premise of To The Moon is based around a technology that allows us to permanently reconstruct the memory on dying man. In this problem, we'll give you a chance, to implement the logic behind the scene.

You‘ve been given N integers A [1], A [2],..., A [N]. On these integers, you need to implement the following operations:
1. C l r d: Adding a constant d for every {A i | l <= i <= r}, and increase the time stamp by 1, this is the only operation that will cause the time stamp increase.
2. Q l r: Querying the current sum of {A i | l <= i <= r}.
3. H l r t: Querying a history sum of {A i | l <= i <= r} in time t.
4. B t: Back to time t. And once you decide return to a past, you can never be access to a forward edition anymore.
.. N, M ≤ 10 5, |A [i]| ≤ 10 9, 1 ≤ l ≤ r ≤ N, |d| ≤ 10 4 .. the system start from time 0, and the first modification is in time 1, t ≥ 0, and won't introduce you to a future state.
 

Input
n m
A 1 A 2 ... A n
... (here following the m operations. )
 

Output
... (for each query, simply print the result. )
 

Sample Input
  
  
10 5 1 2 3 4 5 6 7 8 9 10 Q 4 4 Q 1 10 Q 2 4 C 3 6 3 Q 2 4 2 4 0 0 C 1 1 1 C 2 2 -1 Q 1 2 H 1 2 1
 

Sample Output
  
  
4 55 9 15 0 1
 

Author
HIT
 

Source
2012 Multi-University Training Contest 5
/*
今天学到了一种函数式线段树成段更新时节约内存的办法。
先考虑朴素的仅支持成段加减的线段树,我们可以用方式解决:
1.正常的懒惰标记,当访问到带有懒惰标记节点的子区间时将标记下传;
2.不用下传的懒惰标记,我们用一个标记来记录当前节点的整段区间被累加了多少,
当询问的时候我们在从根节点走到目标结点的过程中不断累加所经过节点上的标记值。
查询历史状态,在线做的话就要用可持久化数据结构,所谓可持久化,意思就是保存
所有的历史状态,但是因为每次修改只涉及到logn个节点,所以每次只新建logn个节点。
其余节点可利用历史版本的。*/
#include<stdio.h>
#define N 3000000//开大点
typedef long long  ll;
int num,rson[N],lson[N],t[N];
ll sum[N],add[N];
int build(int x,int y)
{
   int root=++num;
   add[root]=0;
   if(x==y)
   {
     lson[root]=rson[root]=0;
     scanf("%I64d",&sum[root]);
     return root;
   }
   int mid=(x+y)>>1;
   lson[root]=build(x,mid);
   rson[root]=build(mid+1,y);
   sum[root]=sum[lson[root]]+sum[rson[root]];
   return root;
}
void cop(int now,int root)
{
   lson[now]=lson[root];
   rson[now]=rson[root];
   add[now]=add[root];
   sum[now]=sum[root];
}
int update(int root,int l,int r,int x,int y,int k)
{
     int now=++num;
     cop(now,root);
     if(l==x&&r==y)
     {
        add[now]+=k;
        return now;
     }
     sum[now]+=(ll)(r-l+1)*k;
     int mid=(x+y)>>1;
     if(r<=mid)
       lson[now]=update(lson[now],l,r,x,mid,k);
    else if(l>mid)
       rson[now]=update(rson[now],l,r,mid+1,y,k);
    else
    {
       lson[now]=update(lson[now],l,mid,x,mid,k);
       rson[now]=update(rson[now],mid+1,r,mid+1,y,k);
    }
    return now;
}
ll query(int root,int l,int r,int x,int y)
{
    ll ans=add[root]*(r-l+1);
    if(l==x&&r==y)
    {
      return (ans+sum[root]);
    }
    int mid=(x+y)>>1;
    if(r<=mid)
        ans+=query(lson[root],l,r,x,mid);
    else if(l>mid)
        ans+=query(rson[root],l,r,mid+1,y);
    else
    {
        ans+=query(lson[root],l,mid,x,mid);
        ans+=query(rson[root],mid+1,r,mid+1,y);
    }
    return ans;
}
int main()
{
   int n,m,now,i,l,r,T,d;
   char str[10];
   // freopen("a.txt","r",stdin);
   while(scanf("%d%d",&n,&m)!=EOF)
   {
     num=0;  now=0;
     t[0]=build(1,n);
     for(i=1;i<=m;i++)
     {
        scanf("%s",str);
        if(str[0]=='Q')
        {
          scanf("%d%d",&l,&r);
          printf("%I64d\n",query(t[now],l,r,1,n));
        }
        else if(str[0]=='C')
        {
           scanf("%d%d%d",&l,&r,&d);
           t[now+1]=update(t[now],l,r,1,n,d);
           now++;
        }
        else if(str[0]=='H')
        {
           scanf("%d%d%d",&l,&r,&T);
           printf("%I64d\n",query(t[T],l,r,1,n));
        }
        else
        {
            scanf("%d",&now);
        }
     }
   }
   return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值