主要的目的是記錄一哈二維線段樹,在此之前先簡單總結一下一維線段樹。
線段樹
線段樹顧名思義,處理線段(或者稱爲區間)的整體屬性的一種數據結構。
主要操作爲-範圍更新與查詢,時間複雜度爲logn級別的。
構建過程爲:
這棵樹將所定範圍(區間)不斷進行二分,直至只包含一個值作爲葉節點。
其他的非葉節點表示線段經過二分過後的某個區間。
更新操作:
將所給的區間,與線段樹節點區間比較
所給區間包含樹節點區間,則處理。
區間與樹節點區間不相交,丟掉。
區間有交叉,遞歸到子節點,進行相同步驟。
//有lazy標記優化
目的是當所給區間包含樹節點,不進行子節點的處理,但是做個標記(另開個數組或者加個屬性),表示這些節點是要處理的,但是我們不進行處理,等到查詢的時候進行處理。
查詢操作:
類似
有lazy標記的,則處理後續節點,清除lazy標記,給子節點標記上,逐層進行,如果到了最後一層則不用管lazy標記了。
二維線段樹
基本上是樹套樹,適合矩陣查詢。時間複雜度是logn^2
基本上是在第一層線段樹的基礎上,每個節點的屬性是另一個線段樹。
基本上更新是先按一維查詢,
三種情況中
找到包含的情況後(一維線段樹有講),進行第二維的更新。
下面的代碼是更新操作
const int MAX_N=1<<9; //500個
#define THRES 2*MAX_N
int n,data[2*MAX_N][2*MAX_N];
//省遞歸參數
int yy1,yy2,vv;
void changey(int y1,int y2,int iy,int l,int r,int ix){
int mid=l+r>>2;
//y1<y2
if(y2<l || y1>=r){
return;
}else if(y1<=l && y2>=r){
//todo change data
//data[ix][iy]=vv;
std::function<void(int x)> push_down;
push_down=[&push_down,&ix](int iy){
if(iy<THRES){
data[ix][iy]=vv;
push_down(iy*2);
push_down(iy*2+1);
}
};
push_down(iy);
}else{
int ny1=max(y1,l);
int ny2=min(y2,r-1);
changey(ny1,ny2,2*iy,l,mid,ix);
changey(ny1,ny2,2*iy+1,mid,r,ix);
}
}
void changex(int x1,int x2,int ix,int l,int r){
int mid=l+r>>2;
//x1<=x2
if(x2<l ||x1>=r){
return;
}else if(x1<=l && x2>=r){
//todo
//change y
//changey(yy1, yy2, 1, 0, 501,ix);
//更新完後面的
std::function<void(int x)> push_down,push_down_copy;
push_down=[&push_down](int ix){
if(ix<THRES){
changey(yy1, yy2, 1, 0, 501,ix);
push_down(ix*2);
push_down(ix*2+1);
}
};
push_down(ix);
/*
changey(yy1, yy2, 1, 0, 501,ix);
push_down_copy=[&push_down_copy](int ix){
if(ix<THRES){
copy(begin(data[ix]), end(data[ix]), begin(data[2*ix]));
}
};*/
return;
}else{
int nx1=max(x1,l);
//減1,前開後閉[)
int nx2=min(x2,r-1);
changex(nx1,nx2,2*ix,l,mid);
changex(nx1,nx2,2*ix+1,mid,r);
}
}
//init range 0 - 500
void update(int x1,int x2,int y1,int y2,int v){
yy1=y1;
yy2=y2;
vv=v;
changex(x1,x2,1,0,501);
}
查詢類似
int queryx(int x1,int l,int r,int ix){
int mid=l+r>>2;
if(x1==l==r){
return ix;
}
if(x1<mid){
return queryx(x1,l,mid,2*ix);
}else{
return queryx(x1, mid, r, 2*ix+1);
}
}
int queryy(int y1,int l,int r,int ix,int iy){
if(y1==l==r){
return data[ix][iy];
}
int mid=l+r>>2;
if(y1<mid){
return queryy(y1,l,mid,ix,2*iy);
}else{
return queryy(y1,mid,r,ix,2*iy+1);
}
}
int query(int x1,int y1,int l,int r){
auto ix=queryx(x1, 0, 500, 1);
int v=queryy(y1, 0, 500, ix, 1);
return v;
}