Codeforces - tag::data structures 大合集 [占坑 25 / 0x3f3f3f3f]
371D
小盤子不斷嵌套與大盤子,最后與地面相連,往里面灌水,溢出部分會往下面流,求每次操作時當前的盤子的容量
其實這道題是期末考前就做好了的..
鏈式結構考慮并查集,然后沒了(求大佬解釋第一個T的點)
https://paste.ubuntu.com/p/tFycq2zYqz/
242E
線段樹操作,1.求\([l,r]\)的和,2.更新\(a[l,r]\)為\(a[l,r]⊕x\)
對于操作2,把線段樹拆位后就變為01翻轉操作了
https://paste.ubuntu.com/p/9J73wp4V7V/
1000C
求被1...n次線段覆蓋的各端點個數
口胡一下,離散化亂搞
858D
給出n個定長10的字符串,求每一個字符串的最短可區分子串
把所有的后綴掛到字典樹上,然后n次從小到大暴力枚舉子串,若字典樹中刪去相應的單個子串后不存在或等于自身剩余的相同子串個數,則表明該子串為可識別最短子串
另外解法的細節上的不同是不統計自身相同子串,而是維護前綴串來自于哪個原串,似乎做法這種更優
//此處應有代碼
808D(水)
給定數列\(a[1...n]\),最多可移動一個元素到任意地方,問是否可以把數列分割成連續的兩塊
如果某一塊比另一塊的總和大\(t\),那就看大的那塊有沒有\(t/2\)大小的可移動到另一邊,哈希表O(n)完成
https://paste.ubuntu.com/p/BZCKYHvJgq/
629D
LIS那啥,我討厭這題,不做了
342E
給定一棵n節點的樹,除了1節點為X外其他全為O
有m個操作,操作1為置某節點為X,操作2為詢問某節點與最近的X節點的距離
qls曾說過是樹剖套路題,題解給了一種很好用的分塊暴力方法
對詢問分塊處理,把每\(\sqrt m\)個置X節點存入塊中
每當塊滿了就進行一次\(O(n)\)的bfs更新所有節點的最近距離,然后清空,復雜度\(O(n \sqrt m)\)
否則先取先前一直做好的bfs的最近距離,然后與塊內的置X節點進行暴力LCA詢問取最小距離,復雜度\(O(m \sqrt m)\)
這里忽略詢問節點部分的分塊會使效率高不少
https://paste.ubuntu.com/p/znTK2GzGD3/
670E
給出括號匹配串,求m次操作后(移動和刪除,注意刪除時是匹配的一連串刪除)的匹配串
用棧預處理出所有左右括號匹配的下標,刪除時用并查集相連兩端表示一連串刪除,移動時檢查當前下標并查集是否為空或有刪除標記,有就大幅度滑動,O(n)精神AC
519E
多次詢問一棵樹中到達某兩點u,v距離相等的點的個數
這次做的太糾結了,情況比較麻煩
考慮u,v路徑的長度,若為奇數,則不存在路徑中點,輸出0,
否則就是中點分支上所有點的個數,除去到達u方向的分支和v方向的分支,此時用size來表示就是中點的size減去深度較深的點距中點低一層的祖先的size,即使單鏈也是如此
需要注意的是若中點為LCA要單獨考慮(注意size域的方向),答案為所有的點減去uv兩邊距lca低一層的size
https://paste.ubuntu.com/p/8wMcF8ykwk/
474F
數論不行,只想到了GCD但沒有聯系到區間的最小值
https://blog.csdn.net/S_Black/article/details/47189051
實現比較簡單就不搞了
914D
給定\(a[1...n]\),兩種操作,操作2單點更新,操作1詢問區間gcd能否等于x,詢問過程中可允許暫時修改最多1個數
分析一下,如果某個數不為x的倍數,那么它與任何數gcd都不可能為x,必須要改
如果某個數為x的倍數,那么它可能不改,而由另外一部分限制它因子指數的上限也可以做到gcd為x
因此,在線段樹中查詢區間gcd且統計底層不為x倍數的個數
若個數為0,則證明gcd恰好為x的倍數,雖然不能直接表明相等,但任意修改其中一個數為x那么gcd就為x
若個數為1,我們只能在不為x的倍數的值上修改
其他情況均為非法
https://paste.ubuntu.com/p/MP829x39Yf/
685B
求所有子樹的重心
性質:把兩個樹通過一條邊相連得到一個新的樹,那么新的樹的重心在連接原來兩個樹的重心的路徑上。
遞歸處理
一個點的樹的重心是他自己。
如果一棵樹的根的所有子樹大小都不超過整個樹大小的一半,那么樹根是重心。
否則找到子樹大小超過整個樹大小的一半的子樹(只會有一個),假定當前樹的重心為子樹的重心,用調整的方式得到當前樹的重心。
280B
求\(a[1...n]\)的所有區間的最大值與次大值的最大異或值
這種一般都用到單調棧,只是寫的過程極為混亂ORZ
只要定擴展區間的中心為次大值那就寫起來很輕松了,只需向前向后分別各擴展一次
我怎么就想到定最大值找次大值從左邊枚舉右邊RMQ+二分BLABLA找了呢..
https://paste.ubuntu.com/p/BgHq2bhbkt/
731F
給定\(a[1...n]\),允許選定一個數字,使小于它的數為0,大于它的數變為不超過自身大小的它的倍數,然后累和,求該操作下累和的最大值
用哈希表存儲并統計前綴個數和,類似素數篩地枚舉倍數,分段累和
或者排序然后每次lowerbound查找
https://paste.ubuntu.com/p/h8KkDNshwG/
903D
變種前綴和,求數列\(a[1...n]\)所有區間的差,若兩數相差小于等于1則不計算
算好前綴后再補回不計算的部分就行了,小的減掉,大的加回來
令人惡心的是會爆ll,因此用long double
https://paste.ubuntu.com/p/WGX8brYW74/
367B(水)
給定數列\(a[1...n]\)和\(b[1...m]\)和\(p\),找出符合每項相差p的a子數列使與b匹配
枚舉所有等差長度的數列O(n),是否相等直接用map對比(還挺好用的)
(這題居然能放div1)
https://paste.ubuntu.com/p/xWszDDTgRn/
292E
給定數組\(a[1...n]\)和\(b[1...n]\),
操作1使\(a[L...R]\)快速復制到\(b[k...k+R-L]\),保證操作不越界
操作2查詢\(b[k]\)的值
感覺蠻有創意的一道題,我一開始想到用并查集維護區間信息了(按道理應該可行吧)
另一種思路是用線段樹區間覆蓋,值僅與詢問前最后一次覆蓋到它的更新油管
把\(b\)建成線段樹,只需知道當前節點的開端和復制\(a\)的開端以及自身節點所在的對應數組下標就能推出\(b\)目前的任一點信息
注意沒有更新的特判
具體看代碼
https://paste.ubuntu.com/p/kpNS9cPXn5/
766D
推斷同義詞和反義詞
挑戰程序設計競賽同款題目,略
920F
給定數組\(a[1...n]\),操作1使\(a[L...R]\)變為各自數值對應的因子數\(D[a[i]]\),操作2求和
由于因子數能在\(O(logn)\)時間內降至平凡個數1或者2,直接樹上暴力\(O(nlognlogn)\)
https://paste.ubuntu.com/p/4fMC7HKdfd/
961E
給定\(a[1...n]\),求有多少對\((i,j)\)滿足\(i<j \ \& \ a[i]≥j \ \& \ a[j]≥i\)
沒有第三個條件那是相當好辦,多了那條件就變得極其地繞(我是這么覺得)
首先,要方便地求大小關系和數量關系,樹狀數組是必須的,注意到大于n的都沒用那么把每個元素比較一下取min
求解的方法可以這樣枚舉:\(i\)是一個一個插入的,那么對于\(j,j>i\)而言,求有多少個\(a[1...i_{max,max≤i}]≥j\)的元素
所以我們要維護一個對于每一個j能遍歷到的最遠的i,以滿足\(i≤a[j]\),但因為枚舉過程是i開始的,那么倒過來維護\(vec[maxto:i]={j_1,j_2...}\)
https://paste.ubuntu.com/p/Kr2gV27DHC/
375D
給出一棵有顏色的樹,多次詢問某子樹下相同顏色節點大于某個值的顏色個數
第一反應:樹分塊啊
第二反應:不大會寫hhh
由于是子樹問題,那么可以通過啟發式合并離線處理或者dfs序+線段樹暴力(不大靠譜)解決
先掛著
920E / 190E
給你一個\(n\)個點\(m\)條邊的無向圖,求其補圖的連通塊個數及各個連通塊大小
暴力遍歷
707D
主席樹模板/可持久化KD樹(當我沒說)
Gym - 101142G
題意:給你一棵樹,邊為水流過的路徑,葉子為房子其余為閘開關,有一些搶匪會占領屋子或者撤離屋子,你需要求出每一步最少關閉的水流路徑,其次要求最少誤殺的房屋
正解是直接用DFS序來求,但我嘗試了自己的二分線段樹方法
首先是要解決的是如何表示水流路徑/開關/屋子與誤殺的問題
對原樹求出葉子的標記,開了一棵用于標記是否為葉子的線段樹ori,那么誤殺的房屋=ori線段樹上的區間求和-占領線段樹1的區間求和(由于沒用到快速復原的操作所以線段樹2等價于ori)
我們還多開一棵用于標記總開關的線段樹0,若某節點為1則表示該節點上方的流水被截斷
觀察容易得出每一步操作最多只影響到自身除1以外的最遠祖先,這時候RMQ就派上用場了,但需要改動1以下的兒子的父親為自己,這樣會方便二分
為什么要二分,很顯然占領數從葉子到頂上是一個單調遞增的過程,我們只需找到一個占領最多的lowerbound就可以斷定某一點要斷水流
注意求之前要吧最大子樹的影響清零,如最小誤傷人數要先減除先前誤殺的人數,然后再重新統計誤傷人數
大概思路是這樣,實現過程中注意到了如果刪除某節點后只有另一邊有一個占領點,那詢問的節點的原路徑會錯誤地二分到它的父親,這時要特殊標記一下直接斷定最佳截斷點
目前ans1是正解,不知道ans2錯在哪里了..明天醒來再看吧
https://paste.ubuntu.com/p/4nccbsYyrC/
UPD:我不改了,用正解方法秒A
https://paste.ubuntu.com/p/KvkhyYNqkx/
558E
給你一個僅26字母的串,q次操作,k=1時使[L,R]升序,k=0時降序,求最終的串
使用計數排序和26個線段樹即可
609E
給出一個圖,多次詢問求強制包含(u,v)邊的最小生成樹的權重
先求出MST,若強制包含的邊為MST里的邊那就不作處理,否則必然形成一個包含u,v的環,此時的最小生成樹不同在于必須要刪除環中的最大權邊(環外顯然不受影響)
求的方法常見的對鏈操作有樹鏈剖分,另一種較為巧妙的是倍增法,一邊求祖先一邊更新MST路徑的最大權邊值
//此處應有代碼
689D
已知區間\(a[1...n]\)和\(b[1...n]\),求多少個區間滿足\(max(a[L...R])=min(b[L...R])\)
顯然區間有單調性,枚舉左端點,二分右端點,兩次二分找出最近和最遠的右端點,O(1)或O(logn)計算貢獻即可
587C
一棵樹中的節點帶有權值集合(多個權值),多次詢問求路徑\((u,v)\)的第\(k\)小(\(k<10\),每次均可不同)的權值是多少
k很小,那么每個節點維護一個大小為10的大根堆,樹剖暴力合并,常數應該不爆炸吧?(似乎st表維護堆也行)
明天上代碼
475D
877F
待做(不想做/做不動):644B/359D/755D/830B/487B/777E/724D/514D/637D/721D/534D/754D/893D
834D(unordered)
題意:給出\(a[1...n]\),問劃分成k個連續序列的最大代價,其中每一個序列的代價為序列中不同的數字種類
列出樸素的DP方程\(f[i][j]\):把前\(i\)個數字劃分成\(j\)短的最大代價,轉移\(f[i][j]=max(f[k][j-1]+s[k+1][i])\),其中\(s[i][j]\)表示\(i\)到\(j\)的個數種類
有一種動態維護種類的方法是記錄每個數上一次出現的位置\(last[a[i]]\),每次枚舉到\(i\)時更新\(s[last_{a_i}+1,i]\)加一,那么\(s[j]\)就代表當前\(j\)到\(i\)的種類個數(感覺好神奇
基于這種策略改寫方程:\(f[j][i]=max(f[j-1][k]+s[k+1])\)
第二維可用滾動的線段樹來維護,s直接錯位累加到上一維的\(f[j-1]\)中(直接加一就好)
https://paste.ubuntu.com/p/vJVNK6kMPN/
913D(unordered)
題意:給出n個任務和總時間T,每個任務占時間c_i和要求最后完成的不得超過t_i個任務(包括)才能得1分,求最高得分和方案
倒序枚舉得分k,當t_i≥k時才是有效得分,用平衡樹動態維護前k大的和,具體看代碼
https://paste.ubuntu.com/p/Z3dztvY5Jv/
HDU待做 : 5111/6010/5700
轉載于:https://www.cnblogs.com/caturra/p/9260225.html
總結
以上是生活随笔為你收集整理的Codeforces - tag::data structures 大合集 [占坑 25 / 0x3f3f3f3f]的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 客户端检测的含义和方法
- 下一篇: C# 执行查询语句,返回DataSet