题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4348
题目大意:支持区间求和,成段更新和回到历史版本,访问历史版本。
题目思路:我用的解题报告的离线方法,在线方法不会。。(以下摘自解题报告)
在线方法: 1. 带标记的主席树(利用路径指针实现的函数式的线段树。。 。。可以实现 O(1) 的回档。。和 O(logN) 的询问。。 (但是对内存要求较为苛刻。 2. 主席数组(利用 Fat Node 实现的函数式树状数组。。。 树状数组的每个结点维护一个记录时间戳的栈, 询问的时候用二分查找。总的复杂度 O(nlog^2n)。。。。 对 Backup 操作。。我们使用暴力弹栈。。每个结点至多被弹出一次,总共 O(nlogn) 个结点。。 离线做法: 。。堆维护询问,栈维护操作。。。每次遇到 Backup 操作,则弹出所有至此时刻的询问。。 最后再弹到 0 时刻即可。。每个操作入栈出栈各一次。。复杂度 O(nlogn)。。
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<string> #include<queue> #include<algorithm> #include<vector> #include<stack> #include<list> #include<iostream> #include<map> using namespace std; #define inf 0x3f3f3f3f #define Max 110000 int max(int a,int b) { return a>b?a:b; } int min(int a,int b) { return a<b?a:b; } int val[Max]; __int64 rec[Max]; __int64 ans; struct node { int l,r; __int64 sum,add; int mid() { return (l+r)>>1; } }T[4*Max]; struct op { int tp,t,l,r,d,id; bool operator<(const op a)const { return t<a.t; } }a[4*Max]; void up(int rt) { T[rt].sum=T[rt<<1].sum+T[rt<<1|1].sum; } void down(int rt) { if(T[rt].l==T[rt].r||T[rt].add==0) return; T[rt<<1].sum+=T[rt].add*(T[rt<<1].r-T[rt<<1].l+1); T[rt<<1|1].sum+=T[rt].add*(T[rt<<1|1].r-T[rt<<1|1].l+1); T[rt<<1].add+=T[rt].add; T[rt<<1|1].add+=T[rt].add; T[rt].add=0; } void build(int l,int r,int rt) { T[rt].l=l;T[rt].r=r; T[rt].add=0; if(l==r) { T[rt].sum=val[l]; return ; } int mid=T[rt].mid(); build(l,mid,rt<<1); build(mid+1,r,rt<<1|1); up(rt); } void modify(int l,int r ,int rt,__int64 data) { down(rt); if(T[rt].l==l&&T[rt].r==r) { T[rt].sum+=data*(T[rt].r-T[rt].l+1); T[rt].add+=data; return; } int mid=T[rt].mid(); if(l>mid) modify(l,r,rt<<1|1,data); else if(r<=mid) modify(l,r,rt<<1,data); else { modify(l,mid,rt<<1,data); modify(mid+1,r,rt<<1|1,data); } up(rt); } void query(int l,int r,int rt) { down(rt); if(T[rt].l==l&&T[rt].r==r) { ans+=T[rt].sum; return; } int mid=T[rt].mid(); if(l>mid) query(l,r,rt<<1|1); else if(r<=mid) query(l,r,rt<<1); else { query(l,mid,rt<<1); query(mid+1,r,rt<<1|1); } } char s[10]; int main() { int i,n,m,l,r,d,t; while(scanf("%d%d",&n,&m)!=EOF) { stack<op>stk; priority_queue<op>q; int stamp=0; op opt,tmp; for(i=1;i<=n;i++) { scanf("%d",&val[i]); } build(1,n,1); opt.t=0; opt.l=1;opt.r=n;opt.d=0; stk.push(opt); for(i=0;i<=m;i++) { if(i==m) s[0]='B'; else scanf("%s",s); if(s[0]=='C') { scanf("%d%d%d",&l,&r,&d); modify(l,r,1,d); a[i].l=l;a[i].r=r;a[i].d=-d;a[i].id=i;a[i].tp=0; stamp++; a[i].t=stamp; stk.push(a[i]); } else if(s[0]=='Q') { scanf("%d%d",&l,&r); ans=0; a[i].tp=1; query(l,r,1); rec[i]=ans; } else if(s[0]=='H') { scanf("%d%d%d",&l,&r,&t); a[i].l=l;a[i].r=r;a[i].t=t;a[i].id=i; a[i].tp=2; q.push(a[i]); } else { if(i<m) scanf("%d",&t); else t=0; a[i].tp=3; while(!stk.empty()) { opt=stk.top(); stamp=opt.t; while(!q.empty()) { tmp=q.top(); if(tmp.t<stamp) break; q.pop(); ans=0; query(tmp.l,tmp.r,1); rec[tmp.id]=ans; } if(opt.t==t)break; stk.pop(); modify(opt.l,opt.r,1,opt.d); } stamp=t; } } for(i=0;i<m;i++) { if(a[i].tp==1||a[i].tp==2) printf("%I64d\n",rec[i]); } } }