莫隊演算法---基礎知識介紹(轉載)

来源:http://www.cnblogs.com/chen9510/archive/2016/09/07/5851064.html
-Advertisement-
Play Games

莫隊演算法 莫隊演算法可用於解決一類可離線且在得到區間[l,r][l,r]的答案後,能在O(1)O(1)或O(log2n)O(log2⁡n)得到區間[l,r+1][l,r+1]或[l−1,r][l−1,r]的答案的問題 先看這樣一個問題: 給出n個數字,m次詢問,每次詢問在區間[li,ri][li,ri ...


莫隊演算法

莫隊演算法可用於解決一類可離線且在得到區間[l,r][l,r]的答案後,能在O(1)O(1)或O(log2n)O(log2⁡n)得到區間[l,r+1][l,r+1]或[l1,r][l−1,r]的答案的問題

先看這樣一個問題:

給出n個數字,m次詢問,每次詢問在區間[li,ri][li,ri]之間任選兩個數字相等的概率是多少。(n,q<=50000)(小z的襪子)

在區間[l,r][l,r]中,這個概率是:

vi=1C(2,f(i))C(2,rl+1)∑i=1vC(2,f(i))C(2,r−l+1) (v表示數字值,f(i)表示數字i在區間內出現的次數)

 

由於沒有加和性質,傳統的線段樹什麼的完全派不上用場了呢!

考慮分子,因為C(2,x)=x2x2C(2,x)=x2−x2,所以分子=vi=1f(i)2vi=1f(i)2∑i=1vf(i)2−∑i=1vf(i)2
顯然 vi=1f(i)=rl+1∑i=1vf(i)=r−l+1

若得知區間[l,r][l,r]的答案怎麼求區間[l,r+1][l,r+1]的答案呢?仔細想想。恩,有了。區間[l,r+1][l,r+1]與區間[l,r][l,r]相比只多了一個元素Z,這種改動是很小的,那麼前式中分子的值S=S0f(Z)2+(f(Z)+1)21=S0+2f(Z)S=S0−f(Z)2+(f(Z)+1)2−1=S0+2∗f(Z),同時++f(z),恩,O(1)O(1)的。這樣的話,在處理下一個詢問[li,ri][li,ri]時,複雜度就是O(|rri|+|lli|)O(|r−ri|+|l−li|)的。同樣的方法,也可以在O(1)O(1)內求出[l1,r][l−1,r],[l+1,r][l+1,r],[l,r1][l,r−1]。這樣的方法對於隨機數據表現是很好的,但也不難給出故意卡你的數據。

這時,就需要莫隊演算法來撐腰了,這也是莫隊演算法優化的精髓。

註意到,每個區間可以抽象成平面中的點,每次轉移的花費都相當與從某點到另一點的曼哈頓距離的長度。恩,所以呢?

所以我們花費的便是這些平面中的點聯通的曼哈頓距離。平面點的曼哈頓最小生成樹!

對!但平面點的曼哈頓最小生成樹怎麼求呢?枚舉兩兩點連接O(n2)O(n2),毫無意義。其實平面點的曼哈頓最小生成樹有基於平面區域劃分的O(nlog2n)O(nlog2n)的求法,但我們有更簡潔的方法。對,分塊!

確實,利用分塊,我們可以實現O(nn√)O(nn)的時間複雜度。雖然求解平面點的曼哈頓最小生成樹是O(nlog2n)O(nlog2n)的,但根據莫隊論文中的證明,用到這裡時,仍然是O(nn√)O(nn),只不過常數小一些罷了。

分塊的做法:
x=(√n)x=(n),以[1,x],[x+1,2x],[2x+1,3x]...[1,x],[x+1,2x],[2x+1,3x]...分塊
用pos數組維護端點i在第pos[i]塊中,然後就搞唄。

這樣搞:

1):排序,以左段點所在的塊為第一關鍵字,以右端點為第二關鍵字

2):從左往右處理詢問(離線)

3):不斷調整l,r的位置並同時修改

時間複雜度證明:

右端點移動:
首先我們考慮一個塊裡面的轉移情況
由於一個塊裡面的詢問都按右端點排序
所以我們右端點在一個塊裡面最多移動n次
有 O(n√)O(n)個塊,那麼同一個塊內的右端點移動最多就是O(nn√)O(nn)
然後考慮從一個塊到另一個塊導致的右端點變化
最壞情況,右端點由n到1,那麼移動n次
有 O(n√)O(n)個塊
那麼從一個塊到另一個塊的事件只會發生O(n√)O(n)次……
所以這種右端點移動的次數也是O(nn√)O(nn)次
沒有別的事件導致右端點移動了
左端點移動:
同一個塊裡面,由於左端點都在一個長度為O(n√)O(n)的區間裡面
所以在同一塊裡面移動一次,左端點最多變化O(n√)O(n)
總共有n個詢問……
所以同一塊裡面的移動最多n次
那麼同一個塊裡面的左端點變化最多是O(nn√)O(nn)的
考慮跨越塊
每由第i個塊到第i+1個塊,左端點最壞加上O(n√)O(n)
總共能加上O(n√)O(n)次
所以跨越塊導致的左端點移動是O(n)O(n)的
綜上,分塊做法是O(nn√)O(n∗n)。

總結

莫隊演算法在解決離線區間詢問幾乎是無敵的。
恩,幾乎只要能離線,用分塊的莫隊演算法都能取得一個令人滿意的的解法。
所以就有很多擴展(解決線段樹等數據結構由於需要區間加和性而不能解決的問題),如區間眾數,平均數什麼的。
恩。棒!

附:
[BZOJ]2038 小Z的襪子 分塊 莫隊演算法

#include <cstdio>
#include <cmath>
#include <algorithm>

using namespace std;

const int maxn = 50000 + 500;
typedef long long LL;

LL gcd(LL a,LL b)
{
    return (b==0)?a:gcd(b,a%b);
}

int pos[maxn];
int col[maxn];
int f[maxn];
int n,m;

struct Query
{
    int l,r,id;
    LL a,b;
    friend bool operator < (const Query &R,const Query &T)
    {
        return pos[R.l]<pos[T.l] || (pos[R.l]==pos[T.l] && R.r<T.r);
    }
    void modify()
    {
        LL k=gcd(a,b);
        a/=k,b/=k;
    }
}Q[maxn];
bool cmp_id(const Query &a,const Query &b)
{
    return a.id<b.id;
}

void init()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)
        scanf("%d",&col[i]);
    int limit=(int)sqrt((double)n+0.5);
    for(int i=1;i<=n;++i)
        pos[i]=(i-1)/limit+1;//左端點分塊
    for(int i=1;i<=m;++i)
    {
        scanf("%d%d",&Q[i].l,&Q[i].r);
        Q[i].id=i;
    }
    sort(Q+1,Q+m+1);
}

void modify(int p,LL &ans,int add)
{
    ans=ans+2*add*f[col[p]]+1;
    f[col[p]]+=add;
}

void solve()
{
    LL ans=0;
    int l=1,r=0;
    for(int i=1;i<=m;++i)
    {
        if(r<Q[i].r)
        {
            for(r=r+1;r<Q[i].r;++r)
                modify(r,ans,1);
            modify(r,ans,1);
        }
        if(Q[i].l<l)
        {
            for(l=l-1;Q[i].l<l;--l)
                modify(l,ans,1);
            modify(l,ans,1);
        }
        if(Q[i].r<r)
            for(;Q[i].r<r;--r)
                modify(r,ans,-1);
        if(l<Q[i].l)
            for(;l<Q[i].l;++l)
                modify(l,ans,-1);
        if(Q[i].l==Q[i].r)
        {
            Q[i].a=0,Q[i].b=1;
            continue;
        }
        Q[i].a=ans-(Q[i].r-Q[i].l+1),Q[i].b=(LL)(Q[i].r-Q[i].l+1)*(Q[i].r-Q[i].l);
        Q[i].modify();
    }
    sort(Q+1,Q+m+1,cmp_id);
    for(int i=1;i<=m;++i)
        printf("%lld/%lld\n",Q[i].a,Q[i].b);
}

int main()
{
    init();
    solve();

    return 0;
}

 

Refrence:
http://foreseeable97.logdown.com/posts/158522-233333

http://ydcydcy1.blog.163.com/blog/static/21608904020134411543898/

http://vawait.com/manhattanmst/

http://blog.csdn.net/huzecong/article/details/8576908

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 此bug項目中使用elasticSearch中出現的,原因是,nio事件選擇器,在特性內核下以及jdk6版本中,出現不hold線程,死迴圈獲取事件的bug,導致cup使用率過高; 此bug在官網已被修複:http://bugs.java.com/bugdatabase/view_bug.do?bug ...
  • 一、H5分類 網頁開發,移動開發,移動混合開發, 二、所用知識點: APICloud:APICloud是為了開發APP的,所以如果用H5開發的移動端,需要發送簡訊,獲取照相機等就要用APICloud的了。 aui框架:aui框架就是專門開發移動端的框架。 三、怎樣用H5開發移動端? 我建議如果用H5 ...
  • .NET Getting Started with ASP.NET Core and VS Code Coding Standard Best Practices In C# Wire – Writing one of the fastest .NET serializers Other How D... ...
  • Windows下Nginx配置SSL實現Https訪問(包含證書生成) 首先要說明為什麼要實現https? HTTP全名超文本傳輸協議,客戶端據此獲取伺服器上的超文本內容。超文本內容則以HTML為主,客戶端拿到HTML內容後可根據規範進行解析呈現。因此,HTTP主要負責的是“內容的請求和獲取”。問題 ...
  • 待會蘋果要開發佈會 我寫完這篇文章就準備去看發佈會了,因為我買了好幾包瓜子和啤酒。由於蘋果的保密做的越來越差勁,該曝光的信息差不多全部曝光了,我們這種熬夜看發佈會的只不過是讓這些信息更加真實,或者說是一種習慣了吧,因為每次蘋果和錘子的發佈會都必不可少的守著電腦看。 你要問我最期待什麼新產品?可能是新 ...
  • Django簡介:Django是一個開放源代碼的Web應用框架,由Python寫成。採用了MVC的框架模式,即模型M,視圖V和控制器C。不過在Django實際使用中,Django更關註的是模型(Model)、模板(Template)和視圖(Views),稱為 MTV模式。Django的主要目的是簡便 ...
  • 網上Delphi的Socket伺服器優良代碼,實在少見,索性寫個簡化的非同步Socket伺服器,雖然代碼較少,但卻該有的都有了,使用的是非同步選擇WSAAsyncSelect,減少了編寫線程的繁瑣。可能會問,性能如何?當然使用窗體消息通知,占用的是主線程,偵聽、發送、多個客戶端的接收都一個線程,大量數據 ...
  • 今天在編寫mybatis的mapper.xml時,發現對sql的配置還不是很熟,有很多一坨一坨的東西,其實是可以抽取成服用的。不過良好的組織代碼,還是更重要的。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...