如果乙個問題可以簡單地描述為:對於乙個長度為n陣列,給出m個查詢,每個查詢為區間[l,r]。。。。
顯然,當l=1,r=n時該演算法的時間複雜度為o(n^2),但是通過莫隊演算法改變查詢的順序,我們能夠把時間複雜度降為o(n*√n),此處證明略去。
維護乙個當前的左右端點currentl和currentr,表示當前查詢到的位置,對於第i個查詢區間[l,r]暴力地將currentl和currentr分別移動到l和r,移動中經過的點執行相應的增加(add)或者刪除(del)操作。以上演算法還是o(n^2)的,因為查詢的順序可能雜亂無章。
把[1,n]分為sqrt(n)個區間,依次為1,2...,sqrt(n),每個區間有sqrt(n)個元素。所有查詢按照左端點所在的劃分區間的編號從小到大排序,編號相同的再按照右端點從小到大排序。按照排序完畢的順序依次查詢,演算法的時間複雜度就降為o(n*sqrt(n))
例如n = 9,m = 5的情況 9
1 2 2 5 6 8 5 7 3 5
4 52 3
1 41 2
8 9對查詢區間按劃分區間排序變為[1,4] [1,2] [2,3];[4,5];[8,9]
再次按照右端點劃分變為[1,2] [2,3] [1,4];[4,5];[8,9]
例題nbut1457 sona
給定n(1<=n<=10^5)個數,每個數在1~10^9以內,有q(1<=q<=10^5)個查詢。每次查詢輸出區間內每個數出現次數立方的和。
由於數的大小並不影響答案,我們需要先離散化。那麼每增添乙個數x進來ans=ans-(cnt[x]-1)^3+cnt[x]^3,刪除則相反。
#include#include#include#include#define maxn 100010
using namespace std;
typedef long long ll;
int a[maxn],d[maxn],block,n,q,len,cnt[maxn];
ll ans[maxn],now;
struct q
}que[maxn];
void init()
sort(a+1,a+n+1);
len = unique(a+1,a+n+1)-a;
for(int i = 1; i <= n; i++)
d[i] = lower_bound(a+1,a+len+1,d[i])-a;//d陣列記錄了離散化後a陣列的每個數
scanf("%d",&q);
for(int i = 0; i < q; i++)
sort(que,que+q);
}void add(int x)
void del(int x)
int main()
for(int i = 0; i < q; i++)
printf("%i64d\n",ans[i]);
}}
NBUT 1457 Sona(莫隊演算法)
題意 給定 n 105 的序列,q 105 次詢問 每次 詢問求 l,r 中每個數 字出現次 數的立方 和 分析 離散 化之後莫 隊模版題 vj抓題顯示64 位為ll d,藍兒 其實是i 64d,還 有謎之c e,模版 題坑的一 口老血。created by taosama on 2016 01 2...
NBUT 1457 Sona 莫隊演算法
題意 有n個數,有m個詢問,求每次詢問的區間 l,r 中,每種數字出現次數的立方和 分析 一開始不會莫隊演算法,結果想了很久,分析複雜度之後發現在轉移區間這一塊複雜度很大。後來發現莫隊演算法能很好解決這個問題。那麼就先說一下莫隊演算法吧,其實這個演算法還挺簡單的,能夠離線處理一類區間查詢不修改類問題...
NBUT 1457 莫隊演算法 離散化
題意 求出每乙個區間的能量值,能量值等於所有數字出現次數的三次方之和.很顯然離散化之後記錄下每乙個值出現的次數就能o 1 轉移了,刪除增加不難想.特別坑的是要用 int64,好像n個分數也要用 int64.include include include include include using n...