SPOJ TTM To the moon(主席樹+區間操作)
轉載請註明出處,謝謝http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove
題目:給定一個序列,查詢當前區間和,歷史某個時期的區間和,以前區間修改,時間回滾操作
只要搞過可持久化線段樹,就會覺得這題其實不難吧。。。
按時間,建立主席樹,在上一時間段的基礎上,進行區間更新,生成新的主席樹。
查詢歷史區間什麼的就直接查詢那棵主席樹,時間回滾都很簡單。
但是實現起來就DT了。。。。
寫完也很輕鬆。。。和之前做的主席樹差不多
唯獨這是區間更新。。。問題就在這了。。。
和線段樹上的區間操作累似,對於線段加了lazy操作。
問題就在:如果當前區間更新,加入lazy,按理是不需要更新子節點的,之後直接push_down就行了
這是普通線段樹的做法
但是如果當前區間的左右孩子還是原來的,那麼在查詢的時候,就容易push_down之後更新了歷史版本
在這裡錯了好久,囧。。。。
但是又不能直接更新到所有葉子節點,那就相當於n棵線段樹了。。。n*n*lgn左右的記憶體,吃不消。。
最後只能先指向原來的,但是在父節點上打上標記,表示如果要push_down的話,兩個左右孩子都是歷史版本,不能直接更新
那在push_down之前先判斷是否是虛節點,如果是的話,就新建兩個節點,然後再更新。。。
勉強搞過去了。。。相比於xiaodao的標程來說,記憶體多了好多。。。。(他是動態的)
#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
#include<set>
#include<stack>
#include<string>
#include<ctime>
#include<queue>
#include<cassert>
#define inf 1000000005
#define M 10000005
#define N 110005
#define maxn 210005
#define eps 1e-8
#define zero(a) fabs(a)<eps
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define pb(a) push_back(a)
#define mp(a,b) make_pair(a,b)
#define mem(a,b) memset(a,b,sizeof(a))
#define LL long long
#define MOD 1000000007
#define sqr(a) ((a)*(a))
#define Key_value ch[ch[root][1]][0]
#define test puts("OK");
#define pi acos(-1.0)
#define lowbit(x) ((-(x))&(x))
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
int n,q,a[N];
int T[N],tot,lson[M],rson[M],lazy[M],mark[M];
LL sum[M];
void push_up(int root){
sum[root]=sum[lson[root]]+sum[rson[root]];
}
void push_down(int root,int l,int r){
if(mark[root]){
sum[tot]=sum[lson[root]];
lazy[tot]=lazy[lson[root]];
lson[tot]=lson[lson[root]];
rson[tot]=rson[lson[root]];
lson[root]=tot++;
sum[tot]=sum[rson[root]];
lazy[tot]=lazy[rson[root]];
lson[tot]=lson[rson[root]];
rson[tot]=rson[rson[root]];
rson[root]=tot++;
mark[lson[root]]=mark[rson[root]]=1;
mark[root]=0;
}
if(lazy[root]){
int m=(l+r)>>1;
lazy[lson[root]]+=lazy[root];
lazy[rson[root]]+=lazy[root];
sum[lson[root]]+=(LL)lazy[root]*(m-l+1);
sum[rson[root]]+=(LL)lazy[root]*(r-m);
lazy[root]=0;
}
}
int bulid(int l,int r){
int root=tot++;
lazy[root]=mark[root]=0;
if(l==r){
sum[root]=a[l];
return root;
}
int m=(l+r)>>1;
lson[root]=bulid(l,m);
rson[root]=bulid(m+1,r);
push_up(root);
return root;
}
int update(int root,int L,int R,int l,int r,int val){
int newroot=tot++;
if(L==l&&R==r){
lazy[newroot]=lazy[root]+val;
sum[newroot]=sum[root]+(LL)val*(r-l+1);
if(l!=r){
lson[newroot]=lson[root];
rson[newroot]=rson[root];
mark[newroot]=1;
}
return newroot;
}
lazy[newroot]=0;
sum[newroot]=0;
mark[newroot]=0;
push_down(root,L,R);
int m=(L+R)>>1;
if(r<=m){
lson[newroot]=update(lson[root],L,m,l,r,val);
rson[newroot]=rson[root];
}
else if(l>m){
lson[newroot]=lson[root];
rson[newroot]=update(rson[root],m+1,R,l,r,val);
}
else{
lson[newroot]=update(lson[root],L,m,l,m,val);
rson[newroot]=update(rson[root],m+1,R,m+1,r,val);
}
push_up(newroot);
return newroot;
}
LL query(int root,int L,int R,int l,int r){
if(L==l&&R==r) return sum[root];
push_down(root,L,R);
int m=(L+R)>>1;
if(r<=m) return query(lson[root],L,m,l,r);
else if(l>m) return query(rson[root],m+1,R,l,r);
else return (LL)query(lson[root],L,m,l,m)+query(rson[root],m+1,R,m+1,r);
}
void debug(int root,int l,int r){
cout<<l<<" "<<r<<" "<<sum[root]<<endl;
push_down(root,l,r);
if(l!=r){
int m=(l+r)>>1;
debug(lson[root],l,m);
debug(rson[root],m+1,r);
}
}
int main(){
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
while(scanf("%d%d",&n,&q)!=EOF){
tot=0;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
T[0]=bulid(1,n);
int Time=0;
while(q--){
char str[5];
scanf("%s",str);
int l,r,k;
if(str[0]=='Q'){
scanf("%d%d",&l,&r);
printf("%lld\n",query(T[Time],1,n,l,r));
}
else if(str[0]=='H'){
scanf("%d%d%d",&l,&r,&k);
printf("%lld\n",query(T[k],1,n,l,r));
}
else if(str[0]=='C'){
scanf("%d%d%d",&l,&r,&k);
T[Time+1]=update(T[Time],1,n,l,r,k);
Time++;
}
else{
scanf("%d",&k);
Time=k;
}
}
}
return 0;
}
相關文章
- SPOJ DQUERY (離線數狀陣列||線上主席樹)陣列
- spoj375 樹鏈剖分(單點更新,區間查詢)
- 主席樹
- 主席樹模板
- 線段樹(3)——區間操作疊加
- hdu 2665 可持久化線段樹求區間第K大值(函式式線段樹||主席樹)持久化函式
- 動態主席樹模板
- POJ 3468 A Simple Problem with Integers(線段樹區間操作)
- 樹鏈剖分模板+入門題 SPOJ - QTREEQT
- 演算法:區間樹演算法
- 【資料結構】淺談主席樹資料結構
- 【樹狀陣列 區間更新區間查詢】code陣列
- POJ 3468 【區間修改+區間查詢 樹狀陣列 | 線段樹 | 分塊】陣列
- BZOJ4299: Codechef FRBSUM(主席樹)
- 樹狀陣列的區間查詢與區間修改陣列
- 芻議線段樹 2 (區間修改,區間查詢)
- 演算法隨筆——主席樹(可持久化線段樹)演算法持久化
- hihocoder 1078 線段樹的區間修改 (線段樹 區間更新 模板)
- bzoj3439: Kpm的MC密碼(主席樹+DFS序+字典樹)密碼
- 【主席樹】P3919 【模板】可持久化線段樹 1持久化
- poj 3237 樹鏈剖分(區間更新,區間查詢)
- poj 3468 區間更新 整個區間加一個數和區間求和操作
- 關於區間操作查詢(字首和與差分)+樹狀陣列基礎陣列
- 俄羅斯銀行Sberbank主席:區塊鏈採用需要十年時間區塊鏈
- HYSBZ 2243 樹鏈剖分(區間更新,區間查詢)較難
- 1082 線段樹練習 3 區間查詢與區間修改
- 可持久化線段————主席樹(洛谷p3834)持久化
- 2024年3月21日 懸繩法 + 珂朵莉樹(ODT) + 主席樹
- D 區間求和 [數學 樹狀陣列]陣列
- 線段樹維護區間等差數列
- HDU1698 Just a Hook【線段樹基礎:區間修改+區間查詢】Hook
- NOIP2003加分二叉樹[樹 區間DP]二叉樹
- bzoj4477: [Jsoi2015]字串樹(主席樹+Hash+Lca)JS字串
- Bzoj 1901 Zju2112 Dynamic Rankings(樹狀陣列+主席樹)陣列
- CF 220E Little Elephant and Inversions(主席樹+two points)
- HDU 1754 I Hate It (線段樹 區間最值)
- Java 演算法-區間求和I(線段樹)Java演算法
- HDU 1698 Just a Hook (線段樹區間更新)Hook