有30000
30000
3000
0個佇列,初始每個佇列裡有元素1,2
,3
⋯30000
1,2,3\cdots 30000
1,2,3⋯
3000
0。兩種指令:
1.m mmi
iij
jj 編號為i
ii的佇列整個接到jjj上
2.c cci
iij
jj 問編號為i
ii,j
jj的兩個點之間(不包含i
ii,j
jj)有多少點。(如果不在乙個佇列裡輸出−1-1
−1)輸入
4m 2 3
c 1 2
m 2 4
c 4 2
輸出-1
1這個題目是我在體育課上完成的思路,回來寫的**。。。
趁著剛做完,講講我思考的過程。
剛看到這個題的時候,第乙個想到的肯定是並查集。但是突然注意到詢問是要求中間有多少點,一臉懵逼:這怎麼維護?難道是上splay??(珂是splay我不會啊。。。)
慢慢分析這個題,我們肯定不能暴力維護點的位置。想想那些區間求和的問題,都怎麼做的:沒錯,字首和
\color字首和
字首和!我們用sum
[i
]sum[i]
sum[i]
表示i
ii這個點在i
ii的佇列中前面(不包括i
ii)有多少點。在詢問的時候,只要將兩個sum
sumsu
m值取絕對值相減,然後±
1\pm1
±1或者不變就珂以得到了。究竟是哪個呢?經過對樣例的模擬,我們會發現此時應該是−1-1
−1才是正確的。
上面這個看起來很好理解。那麼如果我們要合併兩個佇列的時候,比方說是x
xx佇列和y
yy佇列,那麼x
xx佇列的每個元素的sum
sumsu
m都因為接在了y
yy佇列的後面,所以每個都要+=c
nt[y
]+=cnt[y]
+=cnt[
y],其中cnt
[y
]cnt[y]
cnt[y]
表示y
yy佇列的元素個數。由於我們需要修改所有x
xx佇列中的元素,遍歷就不珂避免了,一次合併操作就要o(n
)o(n)
o(n)
了。怎麼優化這個呢?
我們想想我們在搞並查集問題的時候都是怎麼搞的:乙個祖先一一對應乙個集合。乙個集合中所有的記錄工作都交給祖
先來完成
\color交給祖先來完成
交給祖先來完
成。所以我們考慮這樣做:只對祖先的sum
sumsu
m加值,在查詢點i
ii的時候逐個加上父親(不包括祖先)的sum
sumsu
m值,就是點i
ii實際的sum
sumsu
m值。然後發現查詢就o(n
)o(n)
o(n)
了,因為我們如果進行路徑壓縮,資訊就丟失了。而實際上,我們珂以在路徑壓
縮的時候
就更新i
點的su
m\color路徑壓縮的時候就更新i點的sum
路徑壓縮的時
候就更新
i點的s
um值,然後讓i
ii就算直接接到祖先上,也不會丟失資料,就保證了資訊的正確性。這很好辦,只要在路徑壓縮回溯的路上順便加上這個值即可。
這樣一次操作就o(1
)o(1)
o(1)
了!!!
**:
#include
#define n 1001000
using
namespace std;
class
dsu}
intfind
(int x)
//找到x的祖先,並將x的sum值設定成所有父親(當然,不包括祖先)
void
merge
(int x,
int y)
//佇列x接到佇列y
}d;void
query()
else
else
//在乙個佇列裡}}
}main()
洛谷 1196 銀河英雄傳說
傳送門 寫題一時wa了時間不多了計畫還沒完成先放下去寫道水題好像是正確的選擇。對每個點記錄它到當前代表元的距離,初始都為0 到自己 合併時之前代表元的距離就等於它要合併的那個集合的size。路徑壓縮時先加上父親到代表元的距離,再把父親換成代表元。twenty include include incl...
洛谷 比賽題解
這套題的題目質量很高,寫一發題解。t1 cjwssb最近在物理學科上遇到了難題,他不會計算乙個電路中的總電阻,現在他找到了你,希望你能幫助他。這個電路有如下限定 1 電路只由導線以及電阻為一歐的電阻組成 2 保證電路從左到右連線,即每個電阻或導線的兩個連線點xy保證x 我們可以用dfs求解,這個電路...
洛谷1087題解
problem description 我們可以把由 0 和 1 組成的字串分為三類 全 0 串稱為b串,全 1 串稱為i串,即含有 0 又含有 1 的串則稱為f串。fbi樹是一種二叉樹,它的結點型別也包括f結點 b結點和i結點三種。由乙個長度為2 n的 01 串s可以構造出一棵fbi樹t,遞迴的構...