題目鏈接: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]);
}
}
}