線段樹著色問題

2021-06-12 19:36:21 字數 2901 閱讀 6580

線段樹節點記錄區間左右座標和區間顏色

如果父節點i表示[left, right],那麼父節點的左節點i*2表示區間[left, mid],有節點表示[mid+1, right],其中mid為left和right的中點

所有的節點存在tree陣列裡面

葉節點表示乙個點,即區間左右座標是一樣的

根節點代表區間[1, l]

三個主要操作:

建樹:初始化函式init(), 根據題目情況修改所代表區間

插入/修改顏色值: insert函式, 引數分別是所需要修改的區間的左右座標,還有修改的顏色值 

預設從根節點開始修改

查詢函式: query函式, 引數分別是所查詢的區間的左右座標,返回該區間含有的不同顏色的數量 

預設從根節點開始找

有些題目資料量過大需要離散化,如果不離散化的話在建樹與插入的時候多了太多的沒必要的搜尋和沒必要的記憶體空間。

假設給定的區間是[1,3],[6,1000],我們可以如下離散

離散前座標:1 3 6 1000

離散後坐標:1 2 3 4

這樣就可以縮小範圍,減少記憶體使用

函式discrete用於離散化

輸入的區間全部存在discretetree,然後放到discretevalue陣列去排序,離散後的區間對應表放在resultvalue陣列

原來的區間與離散後的區間對應關係如右: [discretetree[i].left, discretetree[i].right] 

==> 

[resultvalue[discretetree[i].left], resultvalue[discretetree[i].right]]

注意使用前初始化:

memset(visit, false, sizeof(visit));

l = 20010;//線段樹表示的最大區間[1, l]

init();//線段樹初始化

使用離散化前初始化

memset(discretevisit, false, sizeof(discretevisit));

discretenum = 0;//離散數量清零

int maxx = discrete();//離散獲取離散後的最大值(是為了查詢的時候只在 [1, maxx]裡面查詢 提高效率)

*///pku2528 相當於給區間染色, 統計有多少種不同的顏色

#include

#include

#include

#include

using namespace std;

const int maxn = 10000001;//節點數量

const int discrete_maxn = 10010*2;//離散之後節點數量

const int color_num = 20001;//所染顏色數量

const int default_color = 0;//預設顏色

struct node;

node tree[discrete_maxn*4];

bool visit[color_num];

int l, n;

node discretetree[discrete_maxn*4];//離散點

bool discretevisit[maxn];//標誌離散點

int discretevalue[discrete_maxn*4];//離散值

int discretenum;//離散量

int resultvalue[maxn];//最終離散值

//離散化

//返回離散化後最大的值

int discrete()

if( !discretevisit[discretetree[i].right] )

} sort(discretevalue, discretevalue+discretenum);

int j = 1;

for( i = 0 ; i < discretenum ; i++ )

return j-1;

}//建樹

//引數: 區間左邊座標, 區間右邊座標, 節點下標

void build(const int &left, const int &right, const int &nodenum = 1)

//建樹的初始化函式

void init()

//往線段樹插入資料/修改資料

//引數: 區間左邊座標, 區間右邊座標, 修改的區間顏色, 節點下標

void insert(const int &left, const int &right, const int &color, const int &nodenum = 1)

if (default_color != tree[nodenum].color)

int mid = (tree[nodenum].left + tree[nodenum].right) >> 1;//獲取區間的中點

if (right <= mid)else if (left > mid)else

}//查詢函式

//引數: 

查詢區間左座標, 有座標, 節點下標

//返回: 

查詢區間裡面不同顏色的數量

int query(const int &left, const int &right, const int &nodenum = 1)

return count;

}int mid = (tree[nodenum].left + tree[nodenum].right) >> 1;

if (right <= mid)else if (left > mid)else

return count;

}int main()

printf("%d\n", query(1, maxx));

}return 0;

}--*

線段樹問題

description 給出了乙個序列,你需要處理如下兩種詢問。c a b c 表示給 a,b 區間中的值全部增加c 10000 c 10000 q a b 詢問 a,b 區間中所有值的和。input 第一行包含兩個整數n,q。1 n,q 100000.第二行包含n個整數,表示初始的序列a 1000...

阿里 著色問題

寫出圖著色問題程式 乙個圓餅,被從中點畫半徑分成n等分,有k種顏色,每個區域不能和兩邊顏色相同.include include include include include 將乙個圓形等分城n個小扇形,將這些扇形標記為1,2,3,n。現在使用m種顏色對每個扇形進行塗色,每個扇形塗一種顏色,且相鄰的...

RMQ問題 st 線段樹

j 演算法 rmq range minimum maximum query 問題是指 對於長度為n的數列a,回答若干詢問rmq a,i,j i,j n 返回數列a中下標在 i,j 裡的最小 大 值,也就是說,rmq問題是指求區間最值的問題 主要方法及複雜度 處理複雜度和查詢複雜度 如下 1.樸素 即...