離散化 線段樹儲存區間狀態

2021-12-29 20:08:40 字數 3365 閱讀 7837

時間限制:10000ms

單點時限:1000ms

記憶體限制:256mb

描述小hi和小ho在回國之後,重新過起了朝7晚5的學生生活,當然了,他們還是在一直學習著各種演算法

這天小hi和小ho所在的學校舉辦社團文化節,各大社團都在宣傳欄上貼起了海報,但是貼來貼去,有些海報就會被其他社團的海報所遮擋住。看到這個場景,小hi便產生了這樣的乙個疑問——最後到底能有幾張海報還能被看見呢?

於是小ho肩負起了解決這個問題的責任:因為宣傳欄和海報的高度都是一樣的,所以宣傳欄可以被視作長度為l的一段區間,且有n張海報按照順序依次貼在了宣傳欄上,其中第i張海報貼住的範圍可以用一段區間[a_i, b_i]表示,其中a_i, b_i均為屬於[0, l]的整數,而一張海報能被看到當且僅當存在長度大於0的一部分沒有被後來貼的海報所遮擋住。那麼問題就來了:究竟有幾張海報能被看到呢?

輸入每個測試點(輸入檔案)有且僅有一組測試資料。

每組測試資料的第1行為兩個整數n和l,分別表示總共貼上的海報數量和宣傳欄的寬度。

每組測試資料的第2-n+1行,按照貼上去的先後順序,每行描述一張海報,其中第i+1行為兩個整數a_i, b_i,表示第i張海報所貼的區間為[a_i, b_i]。

對於100%的資料,滿足n<=10^5,l<=10^9,0<=a_i

輸出對於每組測試資料,輸出乙個整數ans,表示總共有多少張海報能被看到。

樣例輸入

5 10

4 10

0 21 6

5 93 4

樣例輸出

5提示一:正確的認識資訊量

小ho聽完小hi的描述,不屑道:「這不就是乙個很簡單的線段樹問題麼,每一張海報其實就是一次修改,**段樹上利用懶惰標記進行維護——「每個節點對應的區間上是否只有一張海報?如果有,是哪一張?」,然後在全部海報處理完成之後,掃瞄一遍整個線段樹,看仍然『存活』的海報有哪些,就可以知道答案了!」

「對,你說的很有道理!」小hi點頭表示贊同,又隨即問道:「但是你這棵線段樹有多大呢?」

「不就是o(n)大小的麼……額,應該是o(l)大小的……因為葉子節點個數是l個,那麼這個樹的空間開出來,似乎記憶體要炸啊。」小ho意識到了問題所在。

「那你準備如何處理?」小hi問道。

「等等,我覺得很不科學啊……你想想,這個問題最關鍵的問題在於這n個區間之間的相互覆蓋關係,而和這n個區間所處的『舞台』也就是這個宣傳欄沒有什麼關係,那麼為什麼解決這個問題的複雜度反倒會和舞台的寬度l有關呢?。」小ho不解道。

小hi點頭道:「對,這就是關鍵問題,[1, 1000000]、[2, 1000001]這兩個區間在這個問題中和[1, 3]、[2, 4]兩個區間其實並沒有什麼不同,但是為了維護前一種情況所需要的線段樹就是非常巨大的。」

小ho沉思半刻,道:「那麼我所需要解決的問題,就是將[1, 1000000]、[2, 1000001]這樣的區間轉化成和它等價的[1, 3]、[2, 4]這樣的區間咯?唔……但是想要弄清楚n個區間之間的關係話,是很複雜的,更何況如果我在弄清楚這n個區間關係的過程中,想必這個題目的問題就已經得到解決了吧?」

小hi笑道:「所以說你走了彎路,太著相於區間這個東西上面了。」

小ho表示理解不能。

小hi便繼續道:「在這個問題的計算過程中,對於這些區間來說,其實並不會在乎具體數值是多少,而是在他們的左右端點之間互相進行比較而已。所以你就把這n個區間的左右端點——2n個整數提出來,處理一下唄?你要注意的是,這2n個數是什麼其實並不重要,你可以把這2n個數替換成為任何另外2n個數,只要他們之間的相對大小關係不發生改變就可以。」

小ho點了點頭,想道:「這2n個數……在數軸上就是最多2n個點,如果我把其中數值最小的點命名為第1個點,簡稱『1』,數值次小的點命名為第2個點,簡稱『2』……依次類推,那麼這些點最多就命名到第2n個點。也就是說他們的數值範圍縮小到了o(n)級別,但是這2n個數的相對大小關係並沒有發生改變。比如說[1, 1000000]、[2, 1000001]、[2, 10]這3個區間的左右端點組成的集合為,那麼我就將這個集合對應到,那麼原來的三個區間就變成了[1, 4]、[2, 5]、[2, 3]這3個區間,但是他們的相互覆蓋關係卻是一點變化都沒有!」

小ho又思考一番,覺得沒有什麼問題,於是道:「那麼我需要額外做的事情就是在構建線段樹之前對區間進行預處理:將區間的左右端點選出來,組成乙個集合,然後將這個集合依次對應到正整數集合上,並且利用這個對應將原來的區間的左右端點更換為新的值。這樣新構建的區間在這個問題中的答案和原來區間是一樣的,但是新區間的範圍就是o(n)這個級別的,我就可以用o(n)的時間複雜度和空間複雜度構建出線段樹了!」

「是的呢!但是你要不要手動寫一下嘗試一下?離散化——將連續的區間轉化成為離散的點在編寫的過程中可還是有很多小問題的哦!」

提示二:小hi大講堂之線段樹的節點意義

**段樹的通常用法中,線段樹的節點是有2種不同的意義的,一種是離散型的,比如在hiho一下 第二十週中,乙個節點雖然描述的是乙個區間[3, 9],但是實際上這樣乙個區間是這樣的意義。而另一種就是連續型的,比如就在這一周的問題中,乙個節點如果描述的是乙個區間[3, 9],它就確確實實描述的是在數軸上從3這個標記到9這個標記的這一段。

那麼有的小朋友可能就要問了,這兩種不同的意義有什麼區別呢?

在小hi看來,其實只有這樣的幾個區別:1.葉子節點:在離散型中,葉子節點是[i, i],而連續性中是[i, i + 1];2.分解區間:在離散型中,一段區間是分解成為[l, m], [m + 1, r],而在連續型中,是分解成為[l, m], [m, r];3.其他所有類似的判定問題。

那麼親愛的小朋友們,你們懂了麼?

和上次的線段樹有一點區別-.-這次儲存的是區間-.-所以二分線段樹時分為了[l , m ] 和 [m , r ]。

**:#include

#include

#include

using namespace std;

int n,m,zuo[100100],you[100100];

bool she[300000];

struct nodeyy[200200];

struct node1yyy[200200];

struct nntrie[300000];

bool cmp(node xx,node yy)

void query(int l,int r,int se,int x)

int m=(trie[x].l+trie[x].r)>>1;

if (trie[x].fafe)

if (r<=m)

query(l,r,se,x*2);

else if (l>=m)

query(l,r,se,x*2+1);

else

update(x);

}void solve(int x)

if (trie[x].fafe)

}int main()

{ scanf("%d%d",&m,&n);

for (int i=0;i

線段樹3(離散化,連續區間)

題目是依次按給定的範圍貼海報,問覆蓋到最後還能看到幾張海報。因為給定的貼海報的板子總長度為10 9,陣列開不下。但是考慮到海報只有10 5張,而整個問題其實課忽略板子長度,只需要考慮每張海報之間的覆蓋關係就可以了,也就是說 1,1000008 3,9990 10,20000000 這三個區間的覆蓋情...

離散化 線段樹

題目 分析 每次1操作會往序列底加first個second,first 和 second 都是最大1e9的資料,每次2操作詢問序列中第first到第second個數的和 一開始就感覺有點像線段樹,輸入資料太大我們可以離線處理把資料離散化下,然後扔到線段樹上,維護兩個陣列 sum 區間數的值的和 nu...

線段樹 離散區間,單點維護區間

這道題當時用線段樹搞不行,用主席樹搞,也不行。當場自閉。其實當時想到離散,但是沒想到用單點維護線段樹的區間。你這樣想,無非就是2e6次詢問,最多1 e9被分成最多2e6區間,我們要求的位置,一定在這2e6點的右邊第乙個。那麼把這個點,以及這個點x以及x 1的點儲存下來。維護的時候,線段樹初始化所有的...