题目链接:To the moon - HDU 4348 - Virtual Judge (ppsucxtt.cn)
题意:
给你一串序列,每次对他有以下四种操作:
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
分析:这是一个可持久化线段树的区间修改+区间查询的裸题,下面直接附上代码,代码里面有注释
这道题目特别需要注意的就是空间,容易超空间
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
typedef long long ll;
const int N=4e6+10,M=1e5+10;
int a[M],ln[N],rn[N],lazy[N],idx;
int root[M];
ll sum[N];
//l和r为当前区间左右端点
void pushup(int id,int l,int r)
{
sum[id]=sum[ln[id]]+sum[rn[id]]+(r-l+1)*lazy[id];
}
void build(int id,int L,int R)
{
lazy[id]=0;sum[id]=0;
if(L==R)
{
sum[id]=a[L];
return ;
}
int mid=L+R>>1;
ln[id]=++idx;rn[id]=++idx;
build(ln[id],L,mid);
build(rn[id],mid+1,R);
pushup(id,L,R);
}
//l和r为当前区间左右端点,L和R为目标区间左右端点
void update_interval(int pre,int id,int L,int R,int val,int l,int r)
{
ln[id]=ln[pre];rn[id]=rn[pre],sum[id]=sum[pre],lazy[id]=lazy[pre];
if(l>=L&&r<=R)
{
lazy[id]+=val;
sum[id]+=(r-l+1)*val;
return ;
}
int mid=l+r>>1;
if(L<=mid) ln[id]=++idx,update_interval(ln[pre],ln[id],L,R,val,l,mid);
if(mid+1<=R) rn[id]=++idx,update_interval(rn[pre],rn[id],L,R,val,mid+1,r);
pushup(id,l,r);
}
//l和r为当前区间左右端点,L和R为目标区间左右端点
ll query_interval(int id,int L,int R,ll lz,int l,int r)
{
if(l>=L&&r<=R) return lz*(r-l+1)+sum[id];
int mid=l+r>>1;
ll ans=0;
if(L<=mid) ans+=query_interval(ln[id],L,R,lz+lazy[id],l,mid);
if(mid+1<=R) ans+=query_interval(rn[id],L,R,lz+lazy[id],mid+1,r);
return ans;
}
int main()
{
int n,m;
char op[5];
while(cin>>n>>m)
{
idx=0;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
root[0]=++idx;
build(root[0],1,n);
int ll,rr,now=0,val,t;
for(int i=1;i<=m;i++)
{
scanf("%s",op);
if(op[0]=='Q')
{
scanf("%d%d",&ll,&rr);
//查询当前时间下的l到r的值的和
printf("%lld\n",query_interval(root[now],ll,rr,0,1,n));
}
else if(op[0]=='C')
{
scanf("%d%d%d",&ll,&rr,&val);
root[++now]=++idx;
//对区间l到r上的值进行修改
update_interval(root[now-1],root[now],ll,rr,val,1,n);
}
else if(op[0]=='H')
{
scanf("%d%d%d",&ll,&rr,&t);
//查询时间t下的l到r的值的和
printf("%lld\n",query_interval(root[t],ll,rr,0,1,n));
}
else
scanf("%d",&t),now=t;//将当前时间返回至t
}
}
return 0;
}