離散化
所謂離散化就是當我們需要存一定數量的陣列時,陣列開不了那麼大,但是數字的種數不多,故離散化就是改變了資料數量的相對大小
去重離散化
給定乙個包含大量重複元素陣列,而我們用到其中的每乙個數即可,去重顯然是更好的選擇
unique函式
標頭檔案:#include
注意:使用前一定要先將無序的列表排序,使重複的元素相鄰
原理:
舉例:int陣列a[7](排過序的):1,1,2,3,3,3,6
使用過unique(a,a+7),陣列變為1,2,3,6,3,3,6
(ps:unique只改變了前4(即不重複元素的個數)個數字,後邊的不變)
而且返回的就是上面標記數字的位址
因此常常用來求出不重複元素:
int a[n];
sort
(a,a+n)
;int num=
unique
(a,a+n)
-a;//按上面例子來看num就是4
for(
int i=
0;i) cout<<為什麼給它起名對映離散化呢,因為這種離散化不減少元素的個數,而且是採用給陣列每個數對映乙個id的方法間接得到我們需要的結果。例如乙個只有四個數的陣列a:
a[i] = 104,1e6,1e8,1e10
而如果我們給每個數乙個對映將a陣列轉化為b[i] = 1,2,3,4,我們可以發現陣列元素之間的相對大小關係是不影響的
還有如果我們要得到一堆資料中每個數i(i很大)作為陣列下標的值,而這些資料總數卻不太多。顯然直接開陣列是存不下的,因此就需要離散化,下面舉乙個很實用的例子
逆序對
對於乙個陣列a若 i > j && a[i] < a[j] 那麼稱a[i]與a[j]是乙個逆序對
其實逆序對就是求每個數前面有多少個比它大的數。暴力求解顯然超時,那麼我們這樣想,如果給定一組亂序數,求解每個數前面有多少比它小的,那麼可以用樹狀陣列。樹狀陣列就是可以很方便維護字首和,從而得到每個數前面有多少比它小的,但是我們如果用陣列存每個數作為下標,開不了很大的陣列怎麼辦?離散化!
究竟如何離散化,我們先給每個數按輸入順序分配乙個id,可以用結構體儲存,例如id1
234a[i]
-11925
那麼我們按a[i]從小到大排序可以得到id1
342a[i]-12
519那麼我們可以發現原始陣列的逆序對數是2,而按id來看得到的逆序對個數也為2。於是我們只要按id作為下標存到樹狀陣列中,我們每次查詢得到某個id前面有多少個比它小的,那麼id-getsum(a[i].id)就可以得到前面有多少個比它大的,但是這樣顯然太麻煩,我們如果直接把a[i]按id從大到小排序,查詢每個id前面都多少個比它大的不就行了?但是這時要注意先更新和先查詢的區別,如果先更新的話,該節點本身以及之前的樹狀陣列對應值都會更新,因此要getsum(a[i].id-1)。但是如果先查詢再更新的話就直接getsum(a[i].id)即可
#include
#include
using namespace std;
#define lowbit
(x)(x&
(-x)
)typedef long
long ll;
const
int maxn=
5e5+10;
struct nodea[maxn]
;int t[maxn]
;ll n;
bool cmp
(node &a,node &b)
void
update
(int i)
}ll getsum
(int i)
intmain()
sort
(a+1
,a+1
+n,cmp)
; ll ans=0;
for(
int i=
1;i<=n;i++
)printf
("%lld\n"
,ans)
;return0;
}
離散化 兩種離散化方式詳解
離散化,就是把一些很離散的點給重新分配。舉個例子,如果乙個座標軸很長 1e10 給你1e4個座標,詢問某乙個點,座標比它小的點有多少。很容易就知道,對於1e4個點,我們不必把他們在座標軸上的位置都表示出來,因為我們比較有多少比它小的話,只需要知道他們之間的相對大小就可以,而不是絕對大小,這,就需要離...
模板 離散化實現的兩種方式
第一種 利用結構體實現離散化 這種方法的弊端是無法辨別重複元素 例如 1 2 2 3 3 離散化之後是 1 2 3 4 5 使用時應注意 include using namespace std const int n 5e5 10 int n int b n struct node sort arr...
離散化的兩種操作
離散化是程式設計中乙個常用的技巧,它可以有效的降低時間複雜度。其基本思想就是在眾多可能的情況中,只考慮需要用的值。離散化可以改進乙個低效的演算法,甚至實現根本不可能實現的演算法。要掌握這個思想,必須從大量的題目中理解此方法的特點。有些資料本身很大,自身無法作為陣列的下標儲存對應的屬性。如果這時只是需...