题目大意
给你n个数,a1~an,你需要实现一下四种操作:
1.C l r d:时间+1,把al~ar全部加上d。
2.Q l r:查询al~ar的和。
3.H l r t:查询在时间t时al~ar的和。
4.B r:返回时间t。
我的做法
可持久化线段树-区间修改
垃圾题卡我内存
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long ll;
int ls[3000010];
int rs[3000010];
int tag[3000010];
ll sum[3000010];
int root[3000010];
int cnt=0;
int build(int l,int r)
{
int p=++cnt;
sum[p]=tag[p]=0;
if(l==r)
{
ls[p]=rs[p]=0;
cin>>sum[p];
return p;
}
int mid=(l+r)>>1;
ls[p]=build(l,mid);
rs[p]=build(mid+1,r);
sum[p]=sum[ls[p]]+sum[rs[p]];
return p;
}
int add(int p1,int l,int r,int v,int L,int R)
{
int p2=++cnt;
ls[p2]=ls[p1];
rs[p2]=rs[p1];
tag[p2]=tag[p1];
sum[p2]=sum[p1];
sum[p2]+=1ll*v*(r-l+1);
if(l<=L&&r>=R)
{
tag[p2]+=v;
return p2;
}
int mid=(L+R)>>1;
if(r<=mid)
ls[p2]=add(ls[p1],l,r,v,L,mid);
else if(l>mid)
rs[p2]=add(rs[p1],l,r,v,mid+1,R);
else
{
ls[p2]=add(ls[p1],l,mid,v,L,mid);
rs[p2]=add(rs[p1],mid+1,r,v,mid+1,R);
}
return p2;
}
ll query(int p,int l,int r,int L,int R)
{
if(l<=L&&r>=R)
return sum[p];
int mid=(L+R)>>1;
ll s=1ll*tag[p]*(r-l+1);
if(r<=mid)
s+=query(ls[p],l,r,L,mid);
else if(l>mid)
s+=query(rs[p],l,r,mid+1,R);
else
{
s+=query(ls[p],l,mid,L,mid);
s+=query(rs[p],mid+1,r,mid+1,R);
}
return s;
}
int main()
{
int n,m;
int t=0;
while(~scanf("%d%d",&n,&m))
{
cnt=0;
int i;
int now=0;
root[0]=build(1,n);
char s[5];
int x,y,z;
for(i=1;i<=m;i++)
{
scanf("%s",s);
if(s[0]=='Q')
{
scanf("%d%d",&x,&y);
cout<<query(root[now],x,y,1,n)<<'\n';
}
else if(s[0]=='C')
{
scanf("%d%d%d",&x,&y,&z);
root[now+1]=add(root[now],x,y,z,1,n);
now++;
}
else if(s[0]=='H')
{
scanf("%d%d%d",&x,&y,&z);
cout<<query(root[z],x,y,1,n)<<'\n';
}
else
scanf("%d",&now);
}
}
return 0;
}