update
\text
update
:我之前講的是個什麼鬼… 如果想看看人話版本 戳這。
感覺自己被坑騙了。。。題目明明寫了所有資料不超過int,敢情是輸入資料不超int???迷惑行為
題目感覺有點繞,我盡量 不口胡。
首先我們搞一顆線段樹1,樹表示插入序列的編號。(如,在q行中第i個出現插入操作)
其實拿到這道題我的本能是樹套樹的。(其實是打樹套樹打瘋了神志不清 )那麼為什麼我們不用樹套樹而可以用簡潔明快的不知什麼鬼演算法呢?我們先想想樹套樹:線段樹1中的每個節點套乙個長度為n的區間,此時的樹套樹其實是可以承受每個點都有不一樣的lazy,value……但不知什麼鬼演算法不一樣,是這樣搞的:我們將長度為n的區間換一下,換成幾個小區間,每個區間不止乙個點,而是一段點有相同的lazy標記。這樣可以保證時空複雜度的可行。
清楚定義後一切就變得 豁, 然, 開, 朗 起來。
思考如何更新。首先,我們知道後面的操作會覆蓋前面的,所以就確定了我們的更新順序:先算左兒子再算右兒子。假設出現了這樣的情況:
|------------|------------------|—| lso根據之前的定義,我們要將a,bnlson
lson
|-------|------------------------|–| rso
nrson
rson
a b cd e
,c,d
,e
a,b,c,d,e
a,b,c,
d,e作為分界線劃分n這個區間作為新的區間。那麼l1l1
l1與l 2l2
l2指標的移動規則不言而喻。
而且我們知道要在r==
cn
tr==cnt
r==cnt
時更新,因為這樣子區間才插入完了,才可以合併。
最後查詢時二分找出pos在被分成的哪段區間裡就行了。
啊我終於講完了謝謝大家祝大家春節愉快闔家幸福有錢出錢沒錢賞贊。
#
include
#include
#define
intlong
long
using
namespace std;
const
int n =
6e5+
2, m = n *30;
int ans, aa, bb, a, b, ql, qr, pos, type, n, m, v[n]
, q, cnt, tot, l[n <<2]
, r[n <<2]
, ll[m]
, rr[m]
, a[m]
, b[m]
;int
read()
while
(s >=
'0'&& s <=
'9')
return x * f;
}void
pushup
(const
int o)
r[o]
= tot;
}void
change
(const
int o,
const
int l,
const
int r)
int mid = l + r >>1;
change
(o <<
1, l, mid)
;change
(o <<1|
1, mid +
1, r);if
(r == cnt)
pushup
(o);
}int
find
(int l,
int r)
return res;
}void
ask(
const
int o,
const
int l,
const
int r)
int mid = l + r >>1;
ask(o <<
1, l, mid)
;ask
(o <<1|
1, mid +
1, r);}
signed
main()
else
}return0;
}
46 清華集訓2014 玄學
一開始腦子進水了 把這題想簡單了 複雜度算錯了 每次都用nlogn的時間修改 而且還狂寫stl 然後就直播自爆8小時qaq。先掛個5分 include include include include include includeusing namespace std define rep i,j,...
題解 清華集訓2014 玄學
題目傳送門 給出乙個 n 個點的序列,有 m 次操作,每次操作為以下兩種 二進位制分組好啊!考慮修改操作,我們發現其實每次修改,都會有一段一段的區間是相同的變化規則,我們可以根據這個將兩個操作進行合併。考慮時間複雜度,你每次增加的時候最多增加 3 段,於是總段數就是 n log 2 n 總時間複雜度...
清華集訓2014 玄學 二進位制分組
鏈結 考慮對操作二進位制分組。每個塊內維護這個區間的操作把整個序列分成的段數 每一段有兩個值a,b a,ba,b代表這一段的真實值為ax bax b ax b 比如相交的兩個操作會形成3段,分別為a1x b a 1x b a1 x b a 1a 2x a 2b1 b2,a 2x b 2a 1a 2x...