【HDU4348】To The Moon-主席树(可持久化线段树)区间修改+区间询问
测试地址:To The Moon
题目大意:维护一个长度为N的数列,支持以下操作:将其中的某个区间内元素加上一个值然后将时间戳+1,询问当前时间戳内某一个区间内元素的和,询问某个时间戳内某一个区间内元素的和,将时间戳重置回某一个前面的时间。
做法:这道题一看就是主席树了,按照主席树区间修改和区间询问的方法去做就行了。但是这道题有点卡空间,如果空间爆了可以用以下方式减少空间的用量:不用下放标记,只需要在询问时实时记录从根到某个节点路径上所有标记的和,就相当于覆盖在这个节点上的标记了,但是要特别注意这种情况下的pushup,在pushup时不要忘了加上该区间原来的标记即可。最后就是注意数据可能爆int,要用long long来存储区间和。
题外话:To The Moon这个游戏我当初玩过,在做题时又看到这个还是挺兴奋的^_^,据说还是国人作品,很厉害啊~
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n,m,a[100010],rt[100010],tot,now;
struct segnode
{
int lc,rc;
long long sum,p;
}seg[4000010];
void buildtree(int &no,int l,int r)
{
no=++tot;
seg[no].lc=seg[no].rc=seg[no].p=0;
if (l==r)
{
seg[no].sum=a[l];
return;
}
int mid=(l+r)>>1;
buildtree(seg[no].lc,l,mid);
buildtree(seg[no].rc,mid+1,r);
seg[no].sum=seg[seg[no].lc].sum+seg[seg[no].rc].sum;
}
void modify(int &no,int last,int l,int r,int s,int t,long long c)
{
no=++tot;
seg[no]=seg[last];
if (l>=s&&r<=t)
{
seg[no].p+=c;
seg[no].sum+=c*(r-l+1);
return;
}
int mid=(l+r)>>1;
if (s<=mid) modify(seg[no].lc,seg[last].lc,l,mid,s,t,c);
if (t>mid) modify(seg[no].rc,seg[last].rc,mid+1,r,s,t,c);
seg[no].sum=seg[seg[no].lc].sum+seg[seg[no].rc].sum+(r-l+1)*seg[no].p;
}
long long query(int no,int l,int r,int s,int t,long long presum)
{
if (l>=s&&r<=t) return seg[no].sum+presum*(r-l+1);
int mid=(l+r)>>1;
long long sums=0;
if (s<=mid) sums+=query(seg[no].lc,l,mid,s,t,presum+seg[no].p);
if (t>mid) sums+=query(seg[no].rc,mid+1,r,s,t,presum+seg[no].p);
return sums;
}
int main()
{
int t=0;
while(scanf("%d%d",&n,&m)!=EOF)
{
t++;
if (t>1) printf("\n");
tot=now=0;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
buildtree(rt[0],1,n);
for(int i=1;i<=m;i++)
{
char op[10];
int a,b,c;
scanf("%s",op);
if (op[0]=='C')
{
scanf("%d%d%d",&a,&b,&c);
modify(rt[now+1],rt[now],1,n,a,b,c);
now++;
}
if (op[0]=='Q')
{
scanf("%d%d",&a,&b);
printf("%lld\n",query(rt[now],1,n,a,b,0));
}
if (op[0]=='H')
{
scanf("%d%d%d",&a,&b,&c);
printf("%lld\n",query(rt[c],1,n,a,b,0));
}
if (op[0]=='B')
{
scanf("%d",&a);
now=a;
}
}
}
return 0;
}