NOIP2017 列队——动态开点线段树
Description:
Sylvia 是一個熱愛學習的女♂孩子。
前段時間,Sylvia 參加了學校的軍訓。眾所周知,軍訓的時候需要站方陣。
Sylvia 所在的方陣中有n×m名學生,方陣的行數(shù)為?n,列數(shù)為?m。
為了便于管理,教官在訓練開始時,按照從前到后,從左到右的順序給方陣中 的學生從 1 到?n×m?編上了號碼(參見后面的樣例)。即:初始時,第?i?行第?j?列 的學生的編號是(i?1)×m+j。
然而在練習方陣的時候,經(jīng)常會有學生因為各種各樣的事情需要離隊。在一天 中,一共發(fā)生了?q件這樣的離隊事件。每一次離隊事件可以用數(shù)對(x,y)(1≤x≤n,1≤y≤m)描述,表示第?x?行第?y?列的學生離隊。
在有學生離隊后,隊伍中出現(xiàn)了一個空位。為了隊伍的整齊,教官會依次下達 這樣的兩條指令:
向左看齊。這時第一列保持不動,所有學生向左填補空缺。不難發(fā)現(xiàn)在這條 指令之后,空位在第?x?行第?m?列。
教官規(guī)定不能有兩個或更多學生同時離隊。即在前一個離隊的學生歸隊之后, 下一個學生才能離隊。因此在每一個離隊的學生要歸隊時,隊伍中有且僅有第?n?行 第?m?列一個空位,這時這個學生會自然地填補到這個位置。
因為站方陣真的很無聊,所以 Sylvia 想要計算每一次離隊事件中,離隊的同學 的編號是多少。
注意:每一個同學的編號不會隨著離隊事件的發(fā)生而改變,在發(fā)生離隊事件后 方陣中同學的編號可能是亂序的。
Hint
Solution
一年前暴力敲了30pts
一年后暴力敲了60pts
沒什么長進啊
還是不會正解。
?
1.不懂樹狀數(shù)組
2.不想寫平衡樹
所以我們寫動態(tài)開點線段樹
?
首先發(fā)現(xiàn),對于x=1的點,可以想到對這個鏈開一棵長度為max(n,m)+q的線段樹。每次找第k個有數(shù)的地方,然后放到最后的位置。
發(fā)現(xiàn),每次向前對齊只有最后一列要動,
向左看齊,只是當前的行會向左移動。
所以,為了便于操作,我們開n+1棵線段樹,前n棵維護i行,1~m-1的答案
最后一棵n+1,維護最后一列n個答案。
?
然后我們就得到了一個優(yōu)秀的MLE做法辣!~~
所以就要動態(tài)開點線段樹。
?
(因為我比較弱)所以簡單講解一下動態(tài)開點線段樹。
發(fā)現(xiàn),有的時候,線段樹需要維護的區(qū)間很大很大,但是實際用到的節(jié)點很少很少。
那么,我們干脆就不要開這么多的節(jié)點,用到的時候再向內存要。
也就是說,我們建立了一棵殘疾的線段樹,缺少很多枝葉,但是絕對夠用了。
畫個圖大概理解一下(雖然也不太對)
實心邊框的點都是我們申請內存給的,虛的點是沒用的。就算申請也不用,實在是浪費資源。
所以,
我們開局只有一個根,裝備葉子全靠給。
例如我們要建立一個權值線段樹,但是在線操作不讓你離散化,值域又是inf級別的,
像這樣,即使這個區(qū)間的范圍很大,但是如果詢問q比較少的話,我們只需要qloginf個節(jié)點,就可以辦到。
?
(發(fā)現(xiàn)和主席樹有點像,但是省空間的思想還是有些不同的。)
?
然后我們用動態(tài)開點線段樹來做這個題。
線段樹根節(jié)點維護的區(qū)間是max(n,m)+q;
開始每個線段樹甚至連根也不用建,需要的時候會建起來。
每個線段樹節(jié)點記錄sz,子樹實際的人數(shù)大小。(開始的時候,只有1~n(m-1)是sz=r-l+1的)
sz可以用一個函數(shù)處理。雖然并沒有這么多的葉子,但是實際上,建出這么多的葉子,也是這個sz(這也是能動態(tài)開點的條件)
再記錄一個val(long long型需注意),記錄當前節(jié)點所代表的人的編號
這個編號val只有在葉子節(jié)點才有用。
?
其實每次詢問引起的變化是:樹x的第y個人走了,進入了樹n+1的末尾,樹n+1的第x走了,進入樹x的末尾。
每次詢問,如果y==m就進入線段樹n+1查詢,否則進入線段樹x查詢,找到答案ans輸出
查詢的時候,順便sz--,刪掉途經(jīng)點的sz(就不用pushup了)
把ans這個編號放進n+1線段樹的末尾(新開一個位置)
同樣,途經(jīng)sz++
如果y!=m說明,第x棵線段樹最后進來一個人。就把n+1的第x個人查詢(刪除),放進線段樹x的末尾(新開一個位置)。
這樣子,其實每棵線段樹根節(jié)點的sz都保持為m-1(或n)
?
Code
?
?
upda:2018.11.2
感覺這個動態(tài)開點線段樹其實不算是典型的動態(tài)開點23333
一般的線段樹都是區(qū)間表示連續(xù)一些下標之類。動態(tài)開點也是如此。
但是這個做法的話,愣是把線段樹寫成了平衡樹的存儲方式。
區(qū)間的長度僅僅代表的是預留空間。
就是把許多點壓成了一個點。
?
轉載于:https://www.cnblogs.com/Miracevin/p/9582412.html
新人創(chuàng)作打卡挑戰(zhàn)賽發(fā)博客就能抽獎!定制產品紅包拿不停!總結
以上是生活随笔為你收集整理的NOIP2017 列队——动态开点线段树的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JAVA加密算法(DSA)
- 下一篇: oracl