二維線段樹

2021-08-21 20:07:07 字數 3190 閱讀 1083

一維線段樹用來維護一維的空間,即乙個線段。

二維線段樹用來維護二維的空間,即乙個矩形。

二維線段樹的每個結點都是一棵一維線段樹,所以結構體陣列要開二維,再加上線段樹本身的性質,會占用很大記憶體,要儘量減少結構體內儲存的值的個數和長度,考慮到每個節點表示的線段的左右端點可以作為函式引數,所以不再儲存在結構體內部,若題目只需儲存乙個值,完全可以只開乙個陣列而不使用結構體。

第一維樹維護的相當於矩形寬的一部分,每個節點對應的二維的線段樹表示在當前寬的這部分裡,長對應的數值。

比如說有乙個2*3的矩陣:12

3456

我們要儲存這個矩陣,需要開二維陣列:

int tree[2*4][3*4];
一維的2表示矩陣的寬,二維的3表示矩陣的長。

一維的線段樹:

其中每個節點都表示乙個二維的線段樹,

tree[1]裡的線段樹表示對於1-2的寬,每個長度區間的對應值

tree[2]裡的線段樹表示對於1-1的寬,每個長度區間的對應值

二維的線段樹:

tree[1][1]表示寬為1-2,長為1-3的矩形,即整個矩形

tree[2][3]表示寬為1-1,長為3-3的矩形

因此,矩陣裡的每個值都存在一維線段樹的葉節點對應的二維線段樹的葉子節點上

即tree[2][4]=1 tree[2][5]=2 tree[3][3]=6

二維線段樹可以用來進行矩形上的點更新,點查詢,區間更新,區間查詢。

點更新點查詢:

每個點由一維的「座標「和二維的」座標「共同構成,查詢時,先在第一維的線段樹上找到對應的葉子節點,再進入葉子節點對應的二維的線段樹中查詢二維座標。

void upda(int i,int x,int nl,int nr,int id)

int mid=(nl+nr)>>1;

if(x<=mid)

upda(i<<1,x,nl,mid,id);

else

upda(i<<1|1,x,mid+1,nr,id);

tree[id][i]=tree[id][i<<1]+tree[id][i<<1|1];

}void updata(int i,int x,int y,int nl,int nr)

int mid=(nl+nr)>>1;

if(x<=mid)

updata(i<<1,x,y,nl,mid);

else

updata(i<<1|1,x,y,mid+1,nr);

}int que(int i,int x,int nl,int nr,int id)

int mid=(nl+nr)>>1;

if(x<=mid)

return tree[id][i].w%2+que(i<<1,x,nl,mid,id);

else

return tree[id][i].w%2+que(i<<1|1,x,mid+1,nr,id);

}int query(int i,int x,int y,int nl,int nr)

區間更新區間查詢:

查詢矩陣x1,y1,x2,y2,先在第一維線段樹中查詢x1-x2區間,再更新相應的線段樹中的y1-y2。

void upda(int i,int l,int r,int nl,int nr,int id)

int mid=(nl+nr)>>1;

if(r<=mid)

upda(i<<1,l,r,nl,mid,id);

else if(l>mid)

upda(i<<1|1,l,r,mid+1,nr,id);

else

}void updata(int i,int l,int r,int nl,int nr,int dl,int dr)

int mid=(nl+nr)>>1;

if(r<=mid)

updata(i<<1,l,r,nl,mid,dl,dr);

else if(l>mid)

updata(i<<1|1,l,r,mid+1,nr,dl,dr);

else

}int que(int i,int l,int r,int nl,int nr,int id)

int mid=(nl+nr)>>1;

if(r<=mid)

return que(i<<1,l,r,nl,mid,id);

else if(l>mid)

return que(i<<1|1,l,r,mid+1,nr,id);

else

return que(i<<1,l,mid,nl,mid,id)+que(i<<1|1,mid+1,r,mid+1,nr,id);

}int query(int i,int l,int r,int nl,int nr,int dl,int dr)

int mid=(nl+nr)>>1;

if(r<=mid)

return query(i<<1,l,r,nl,mid,dl,dr);

else if(l>mid)

return query(i<<1|1,l,r,mid+1,nr,dl,dr);

else

return query(i<<1,l,mid,nl,mid,dl,dr)+query(i<<1|1,mid+1,r,mid+1,nr,dl,dr);

}

區間更新點查詢時可以不斷累加路徑上的價值

要特別注意的是,區間更新時要把子節點對應的樹上的價值更新到父節點對應的樹上,這樣在區間查詢時才能保證較小的複雜度

void up(int i,int x,int nl,int nr,int id)

void updata(int i,int x,int y,int nl,int nr)

int mid=(nl+nr)>>1;

if(x<=mid)

updata(i<<1,x,y,nl,mid);

else

updata(i<<1|1,x,y,mid+1,nr);

up(1,y,1,m,i);

}

二維線段樹

二維線段樹一般用樹套樹的方式實現,每個外層線段樹的節點對應一顆內層線段樹,整個線段樹存放在乙個二維陣列中。二維線段樹 poj2155 include include include include include include include include include include inc...

二維線段樹

二維線段樹矩陣區間查詢最大值 矩陣求和預處理後o 1 就能算出來,不用線段樹,除非有修改操作 先第一維在第二維,注意建樹有個順序問題,應該讓第一維度的先建完然後再建第二個維度 具體看 include include include using namespace std const int maxn...

二維 MLE 線段樹

關於二維線段樹,ta死了 先來看看兩種二維線段樹的打法 1.四叉樹 然而ta死了,ta是 theta n 的,加上線段樹的常數,t 飛穩 2.線段樹套線段樹 我盡量畫出來.圖中每個方塊是一棵線段樹 畫完長這樣 你們湊合看吧,作者已經半卒了 區域性放大圖 現在每個圓點代表真正的乙個點 接下來的講解以今...