傳送門
題目大意
給出乙個序列,有以下兩種操作:
解題思路
很好的一道題,之前在洛谷寫過查詢區間內是否有兩數相同是用莫隊維護的區間種類數,但是本題如果寫莫隊估計要tle
tletl
e,然後學到了這手很強的問題轉化技巧:
對於區間內的每個數,我們只需要知道它右邊離他最近相同數的在哪個位置,然後判斷區間內的最小值是否在區間內。(或者等價的,查詢每個數左邊相同數的位置最大值是否在區間內)。那麼這時刪除乙個數,只需要像雙向鍊錶那樣刪除就行,因此需要兩個陣列l,r
l,rl,
r分別記錄每個數最左邊和最右邊相鄰的數,需要注意鍊錶首尾節點的刪除要特判一下,刪除節點就單點更新其最右邊的相同的數為無窮。
#include .h>
#include
using namespace std;
#define endl "\n"
typedef long
long ll;
const
int inf =
0x3f3f3f3f
;const
int maxn =
5e5+10;
const
int mod =
1e9+7;
int n;
int a[maxn]
, l[maxn]
, r[maxn]
, pre[maxn *2]
;int tree[maxn <<2]
;void
build
(int i,
int l,
int r)
int mid =
(l + r)
>>
1, k = i <<1;
build
(k, l, mid)
;build
(k |
1, mid +
1, r)
; tree[i]
=min
(tree[k]
, tree[k |1]
);}void
change
(int i,
int l,
int r,
int pos,
int x)
int mid =
(l + r)
>>
1, k = i <<1;
if(pos <= mid)
change
(k, l, mid, pos, x)
;else
change
(k |
1, mid +
1, r, pos, x)
; tree[i]
=min
(tree[k]
, tree[k |1]
);}int
query
(int i,
int l,
int r,
int x,
int y)
intmain()
memset
(pre,
0x3f
, sizeof pre)
;for
(int i = n; i >=
1; i--
) r[i]
= pre[a[i]
], pre[a[i]
]= i;
//for (int i = 1; i <= n; i++) cout << l[i] << " "; cout << endl;
//for (int i = 1; i <= n; i++) cout << r[i] << " "; cout << endl;
build(1
,1, n)
;while
(q--)}
else
else
} l[l]
= r[l]
= inf;
change(1
,1, n, l, inf);}
else
}return0;
}
買禮物 鍊錶 線段樹)
在賣禮物的超市中有n個櫃子,每個櫃子裡都擺放了乙個禮物,每個禮物有自己的乙個編號,第i個櫃子裡的禮物編號為ai 茶山牛想給牛牛和牛妹買相同編號的禮物,但禮物有可能在某個時刻被其他人買走,而且櫃子數量太多,因此茶山牛在某個時刻只想知道某乙個櫃子區間是否能買到兩件相同編號的禮物。具體來說,有q次操作,格...
買禮物 題解 線段樹 思維
本質上還是乙個線段樹裸題 就是要思考這個線段樹記錄的是什麼 線段樹記錄區間中每個元素的下乙個元素的最小值 這樣只要查詢的時候小於右邊界即可 而如果把某個值變為空,即模擬一下鍊錶操作即可 那麼就變成了單點修改,區間查詢 include define fi first define se second ...
線段樹 買水果
水果姐今天心情不錯,來到了水果街。水果街有n家水果店,呈直線結構,編號為1 n,每家店能買水果也能賣水果,並且同一家店賣與買的 一樣。學過oi的水果姐迅速發現了乙個賺錢的方法 在某家水果店買乙個水果,再到另外一家店賣出去,賺差價。就在水果姐竊喜的時候,cgh突然出現,他為了為難水果姐,給出m個問題,...