【快速處理】分塊算法


分塊算法

----------------------------------------------------------

1.思想

如果我們需要對一個特定的序列進行操作,那么非常直觀、簡單的方法就是純暴力(不,那叫模擬)。

不過如果暴力能過的話,那就呵呵了。

所以我們要想一些比較高能的數據結構——分塊。

相比線段樹來說,分塊算法比較難實現,但是只要深入理解,就可以實現了,只不過需要一些數據結構的輔助。

 

分塊實質來說就是把一個序列切分,從而實現對查詢、查找、替換等等操作的高效處理。

 

----------------------------------------------------------

 

2.輔助結構

我們知道,數組的單點查詢時間為O(1),而插入為O(n)

                鏈表的單點查詢時間為O(n),而插入為O(1)

 

而在NOIP里,vector總體來說是比數組快的,所以我們可以用vector來儲存每塊,只不過如果讓插入也這用vector的話,那么時間就不可理喻了。

插入的話,我們可以使用pair

 

通常要定義這兩個數據結構,簡單的話那個pair就不用了,這要根據題意定義。

 

----------------------------------------------------------

3.模版

 

操作:建塊(rebuild)

注意:一開始不必要建塊,但是要在過程中將序列分塊

用途:當當前塊太大時,可以使用此函數將一個大塊分裂

void rebuild()
{
    top=0;
    for(int i=1;i<=m;i++)
    {
        for(vector<int>::iterator j=ve[i].begin();j!=ve[i].end();j++)
            st[++top]=*j;
        ve[i].clear();//清空當前塊
    }
    int blo2=sqrt(top);
    for(int i=1;i<=top;i++)
        ve[(i-1)/blo2+1].push_back(st[i]);
    m=(top-1)/blo2+1;
}

  

操作:區間加法(add)

注意:blo是分塊一個重要的變量,是N的開方,大家可以仔細想一想為什么

用途:在需要操作區間加法時可以使用

void add(int a,int b,int c)
{
    for(int i=a;i<=min(bl[a]*blo,b);i++)
        v[i]+=c,sum[bl[a]]+=c;;
    if(bl[a]!=bl[b])
        for(int i=(bl[b]-1)*blo+1;i<=b;i++)
            v[i]+=c,sum[bl[b]]+=c;
    for(int i=bl[a]+1;i<=bl[b]-1;i++)
        atag[i]+=c;
}

  

操作:插入

注意:自己可以控制塊的大小

用途:插入元素

 

void insert(int a,int b)
{
    pair<int,int> t=query(a);
    ve[t.first].insert(ve[t.first].begin()+t.second,b);
    if(ve[t.first].size()>20*blo)//分裂大塊
        rebuild();
}

 

 

常用的分塊只有這幾個操作,更多操作可見hzwer

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM