在原數列第 \(i\) 個後面新增乙個新元素 \(k\);如果原數列的第 \(i\) 個元素已經新增了若干元素,則新增在這些元素的最後。
查詢相鄰兩個元素的差值的絕對值的最小值。
查詢所有元素中一對元素的差值的絕對值的最小值。
第乙個操作很好維護,若要在第 \(i\) 個元素後面插值,那麼實際需要插入的位置是 \(i+s_i+1\) ,其中 \(s_i\) 表示原數列第 \(i\) 個數及以前的數後面一共插了多少個數。若 \(s_i\) 加一,那麼 \(s_~s_n\) 都會加一,顯然可以用樹狀陣列做。
第三個操作也好維護,建一棵以值為關鍵字的平衡樹即可。每次插入新元素時,查詢前驅後繼,更新答案。
關鍵在於第二個操作,一開始我想的和第三個操作一樣,再建一棵以位置為關鍵字的平衡樹,查前驅後繼更新答案。但這顯然是不對的,因為當乙個數 \(a\) 插入到 \(b\) 和 \(c\) 中間時,\(b\) 的後繼和 \(c\) 的前驅會變,而之前的答案很可能是 \(|b-c|\)。我們換個思路,考慮多維護一些值 \(pre\)、\(nex\)、\(gap\) 分別表示乙個數和前驅的差值、和後繼的差值、整棵子樹中 \(pre\) 和 \(nex\) 的最小值的最小值。當乙個數被插入時,有且僅有 \(3\) 個數的前驅和後繼發生變化,而對於每個更改,只會修改一條鏈,所以我們記錄乙個 \(fa\) ,每次更新完乙個節點後都從當前節點跳 \(fa\) 並 \(update\)。最後的答案就是 \(gap[root]\)
inline void update(int id)
若平衡樹為空,查前驅後繼的時候可能會出問題,\(gap\) 的值也可能出問題,故預先插入乙個 \(-inf\) 和 \(inf\)。
兩顆平衡樹可以用 \(struct\) 分開寫,這樣思路清晰不容易掛。
#include#include#include#define n 1000007
#define lid s[id][0]
#define rid s[id][1]
#define inf (1<<30)
int n,m;
inline int read()
while(c>='0'&&c<='9')
return tag? x:-x;
}inline int abs(int x)
inline int min(int x,int y)
}void print(int id)
}a;struct fhq_val
inline void update(int id)
inline int new(int x)
int merge(int x,int y)
}void print(int id)
}b;int sort_gap=inf;
inline void update(int id)
int main()
a.rt=a.merge(a.rt,a.new(inf));
char op[10]=;
for(int i=1;i<=m;i++)else if(op[4]=='g') printf("%d\n",a.gap[a.rt]);
else printf("%d\n",sort_gap);
}}/*
3 55 3 1
insert 2 9
min_sort_gap
insert 2 6
min_gap
min_sort_gap
*/
ZJOI2007 報表統計
不想描述了,心累。兩個操作分別用splay和線段樹來維護 全域性的差值最小直接用splay在插入的時候維護前驅後繼即可 相鄰最小差值我們可以這樣搞 首先 用線段樹維護相鄰的最小值 可以注意到插入元素的操作,如果是在乙個元素之後反覆插入,這些元素之間更新出來的最小值是不會發生改變的。只有元素與元素之間...
ZJOI2007 報表統計
題解 一道不錯的模板題 對於第乙個詢問,只需維護乙個支援刪除的堆 方法1.再維護乙個堆,將刪除的數加入這個堆,每次取元素時判斷一下是否和另乙個堆相等 方法2.利用左偏樹可以刪除任意節點 太久不寫都忘了 當然也可以維護一顆平衡樹 對於第二個詢問,只需弄一顆平衡樹求它的前驅後繼就可以了 include ...
ZJOI 2007 報表統計(multiset)
題目鏈結 點我點我 題目描述 q的媽媽是乙個出納,經常需要做一些統計報表的工作。今天是媽媽的生日,小q希望可以幫媽媽分擔一些工作,作為她的生日禮物之一。經過仔細觀察,小q發現統計一張報表實際上是維護乙個非負整數數列,並且進行一些查詢操作。在最開始的時候,有乙個長度為n的整數序列,並且有以下三種操作 ...