HDU4348 To the moon
阿新 • • 發佈:2018-12-12
題目大意:給你n個數,開始時間為0,按照操作輸出
給你四種操作:
1、C l r d : 在(l,r)區間都加上d,++時間戳
2、Q l r : 詢問現在(l,r)的區間和
3、H l r t : 詢問在t時間的(l,r)的區間和
4、B t : 直接回到t的時間
主席樹維護區間標記,標記永久化來寫。pushdown的話會多開許多節點,很難受。
記住一句話:更新節點要新開節點維護,而我們想要做的就是通過共用版本,儘量少開節點。
#include<bits/stdc++.h> using namespace std; const int Maxn=100005; int n,m,a[Maxn]; int cnt,root[Maxn]; struct SegMent{ struct tree{ int l,r,ls,rs; long long sum,tag; }t[Maxn*20]; #define maintain(x) t[x].sum=t[t[x].ls].sum+t[t[x].rs].sum void build(int &x,int l,int r){ t[x=++cnt]=(tree){l,r,0,0,0}; if(l==r)return t[x].sum=a[l],void(); int mid=l+r>>1; build(t[x].ls,l,mid),build(t[x].rs,mid+1,r); maintain(x); } void add(int &x,int o,int l,int r,int k){ if(t[o].l>r||t[o].r<l)return ; t[x=++cnt]=t[o]; if(l<=t[x].l&&t[x].r<=r){ t[x].sum+=1ll*k*(t[x].r-t[x].l+1); t[x].tag+=k; return ; } if(t[x].l<=l&&l<=t[x].r&&t[x].r<=r){ t[x].sum+=1ll*k*(t[x].r-l+1); }else if(l<=t[x].l&&t[x].l<=r&&r<=t[x].r){ t[x].sum+=1ll*k*(r-t[x].l+1); }else { t[x].sum+=1ll*k*(r-l+1); } add(t[x].ls,t[o].ls,l,r,k),add(t[x].rs,t[o].rs,l,r,k); } long long query(int x,int l,int r,int tag){ if(t[x].l>r||t[x].r<l)return 0; if(l<=t[x].l&&t[x].r<=r) return 1ll*t[x].sum+1ll*tag*(t[x].r-t[x].l+1); return query(t[x].ls,l,r,tag+t[x].tag)+query(t[x].rs,l,r,tag+t[x].tag); } }seg; int main(){ // cout<<sizeof(seg.t)/1024/1024; while(scanf("%d%d",&n,&m)!=EOF){ for(int i=1;i<=n;++i)scanf("%d",&a[i]); memset(seg.t,0,sizeof(seg.t)); cnt=0;seg.build(root[0],1,n); int cur=0; for(int i=1;i<=m;++i){ char c=getchar();while(!isalpha(c))c=getchar(); if(c=='C'){ ++cur;int a,b,d;scanf("%d%d%d",&a,&b,&d); seg.add(root[cur],root[cur-1],a,b,d); }else if(c=='Q'){ int l,r;scanf("%d%d",&l,&r); cout<<seg.query(root[cur],l,r,0)<<'\n'; }else if(c=='H'){ int l,r,t;scanf("%d%d%d",&l,&r,&t); cout<<seg.query(root[t],l,r,0)<<'\n'; }else { scanf("%d",&cur); cnt=root[cur+1]-1; } } } return 0; }