vjudge: spoj--to the moon(主席树区间修改)

来源:互联网 发布:股票看行情软件 编辑:程序博客网 时间:2024/05/17 08:53

题目大意:

       题目大意:给定一些数字,有以下几个操作

       a、[L,R]区间的数字变化D的数值。并且时间向前推进

       b、询问某个时间的[L,R]区间的数字之和,这不花费时间

       c、回到X时间。

 

 

可持久话线段树裸题。

 

其实区间修改就体现了,只要主席树更新的节点,就要重建。

就本题而言,区间加我可以搞成标记永久化,防止pushdown新建太多的节点,感觉尽量不要通过pushdown加太多节点,想办法搞成标记永久化

 

#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<algorithm>#include<stack>using namespace std;const int N=100005;typedef long long ll;struct aa{int lc,rc,l,r;ll add,sum;int len(){return r-l+1;}}a[N*4*200];int n,m,rt[N],time,tot;void build(int &u,int l,int r){u=++tot;a[u].l=l,a[u].r=r;if (l==r) {scanf("%lld",&a[u].sum);return ;}int mid=(l+r)>>1;build(a[u].lc,l,mid);build(a[u].rc,mid+1,r);a[u].sum=a[a[u].lc].sum+a[a[u].rc].sum;}void insert(int &now,int old,int l,int r,ll d){now=++tot;a[now]=a[old];if (a[old].l==l&&a[old].r==r){a[now].add+=d;return;}a[now].sum+=d*(r-l+1);int mid=(a[now].l+a[now].r)>>1;if (r<=mid) insert(a[now].lc,a[old].lc,l,r,d);else if (mid<l) insert(a[now].rc,a[old].rc,l,r,d);else {insert(a[now].lc,a[old].lc,l,mid,d);insert(a[now].rc,a[old].rc,mid+1,r,d);}}ll query(int u,int l,int r){ll tmp=a[u].add*(r-l+1);if (a[u].l==l&&a[u].r==r) return a[u].sum+tmp;int mid=(a[u].l+a[u].r)>>1;if (r<=mid) return tmp+query(a[u].lc,l,r);else if (mid<l) return tmp+query(a[u].rc,l,r);return tmp+query(a[u].lc,l,mid)+query(a[u].rc,mid+1,r);}int back[N];int main(){scanf("%d%d",&n,&m);build(rt[0],1,n);time=0;char ch[2];int x,y,t;ll d;for (int i=1;i<=m;i++){scanf("%s",ch);switch(ch[0]){case 'C':scanf("%d%d%lld",&x,&y,&d);time++;insert(rt[time],rt[time-1],x,y,d);back[time]=tot;break;case 'Q':scanf("%d%d",&x,&y);printf("%lld\n",query(rt[time],x,y));break;case 'H':scanf("%d%d%d",&x,&y,&t);printf("%lld\n",query(rt[t],x,y));break;case 'B':scanf("%d",&time);tot=back[time];break;}}return 0;}


 

 

 

0 0
原创粉丝点击