1. 程式人生 > 實用技巧 >張 家 港 辦 證x

張 家 港 辦 證x

離散化

蒟蒻因為即將學習主席樹,發現離散化這個東東不太會,所以寫一篇部落格記錄一下。

概念

離散化,就是把無限空間中有限的個體對映到有限的空間中去,以提高演算法的時空效率。(來自百度百科

作用

​ 很多演算法的複雜度與資料中的最大值有關,比如樹狀陣列和純用陣列實現的一對一標記。時常會遇到這種情況:資料的範圍非常大或者其中含有負數,但資料本身的個數並不是很多(遠小於資料範圍)。在這種情況下,如果每個資料元素的具體值並不重要,重要的是他們之間的大小關係的話,我們可以先對這些資料進行離散化,使資料中的最大值儘可能小且保證所有資料都是正數。

​ 例如,有這樣一個長為5的序列:102131511,123,9813186,-611,55。其中有非常大的數以及負數,會給許多演算法的實現帶來困擾,我們可以把這個序列離散化,使它變成這樣:5,3,4,1,2。各個元素間的大小關係沒有任何改變,但資料的範圍一下子就變得很舒服了。

程式碼實現

普通離散化
int n, a[maxn], t[maxn];
//這裡以下標1為序列的起點,一般情況下從0開始也可以
for(int i = 1;i <= n;i++)
{
    scanf("%d", &a[i]);
    t[i] = a[i];//t是一個臨時陣列,用來得到離散化的對映關係
}
//下面使用了STL中的sort(排序),unique(去重),lower_bound(查詢)函式
sort(t + 1, t + n + 1);//排序
int m = unique(t + 1, t + 1 + n) - t - 1;//去重,並獲得去重後的長度m
for(int i = 1;i <= n;i++)
    a[i] = lower_bound(t + 1, t + 1 + m, a[i]) - t;//通過二分查詢,快速地把元素和對映對應起來
座標離散化
//對x1和x2進行座標離散化,並返回離散後的寬度。(對於y1,y2同理)
//將x1,x2更新為離散後的x1,x2.y不變在x方向上縮小。(處理y1,y2時同理)
int compress(int *x1,int *x2,int w)
{
    vector<int> xs;
    for(int i = 0;i < N;i++)//確定離散後x軸上哪些值還存在
    {
        for(int d = -1;d <= 1; d++)
        {
            int tx1 = x1[i] + d, tx2 = x2[i] + d;
            if(1 <= tx1 && tx1 <= w) xs.push_back(tx1);
            if(1 <= tx2 && tx2 <= W) xs.push_back(tx2);
        }
    }
    sort(xs.begin(),xs.end());
    xs.erase(unique(xs.begin(),xs.end()),xs.end());//去重
    for(int i = 0; i < N; i++)//轉化為新的x1,x2;
    {
        x1[i] = find(xs.begin(),xs.end(),x1[i])-xs.begin();
        x2[i] = find(xs.begin(),xs.end(),x2[i])-xs.begin();
    }
    return xs.size();
}

放一個例題:P1955 [NOI2015]程式自動分析

思路和程式碼在這裡