莫隊演算法 uva 12345

2021-08-07 19:42:30 字數 1735 閱讀 7494

第一道帶修改的莫隊。學習ing

傳送門:dynamic len(set(a[l:r]))

當然也可以訪問vjudge。 另類傳送門

題意:

有乙個序列,對於這個序列有兩種操作。

1、詢問[l, r]這個區間裡有多少個不同的數

2、修改某個位置的值。

如果沒寫過莫隊的修改,應該會能想到樹套樹(orz但是本人蒟蒻不會寫樹套樹啊)。

但是有了莫隊之後情況就不一樣了。**量比樹套樹要少很多。

莫隊的修改:

分塊的時候要分成 2 / 3塊(沒證明過)。

時間複雜度為n5

3

分塊排序的時候,先按左端點的塊排序,再按右端點的塊排序。

最後按修改時間排序。

這裡的修改時間為,這個詢問操作前面出現過多少次修改操作。

對於每一次查詢,先將他退回或前進到修改的時間。

再進行分塊的查詢。有沒有一點時光倒流的感覺呢。

這裡要注意,以前寫莫隊每太在意l指標和r指標的交錯,這道題如果移動的時候交錯了就會wa。

所以,我們應該優先移動r指標向右,再移動l指標向左,剩下兩個隨意操作。

這要能保證這兩個指標不會錯位。就是不會出現r < l的情況

#include 

#define maxn 1000005

using namespace std;

struct question qsn[maxn];

struct modify mod[maxn];

intpos[maxn];

int flag[maxn];

int a[maxn];

int lans[maxn];

intlast[maxn];

bool mark[maxn];

intq, ans, n, cnt;

int cmp(question a, question b)

if (pos[a.r] != pos[b.r])

return a.time

< b.time;

}void clear()

void add(int

x) flag[a[x]]++;

mark[x] = true;

}void del(int

x) mark[x] = false;

}void modify(int

x, int v) else

}void solve()

while (time > qsn[i].time)

while (r < qsn[i].r)

while (l > qsn[i].l)

while (r > qsn[i].r)

while (l < qsn[i].l)

lans[qsn[i].idx] = ans;

}for (int i = 1; i <= q; i++)

}int main()

clear();

for (int i = 1; i <= m; i++) else

}solve();

}}/*

7412

1321

4q 1

6m 3

2q 1

6q 3

5*/

樹上莫隊演算法

繼續回來寫部落格 記錄點有意思的題目什麼的。貌似寫過這個的沒多少人 所以我也記錄一點。首先序列上的莫隊大家都應該很熟悉了 那麼樹上的莫隊要怎麼搞呢?先來看個題目 spoj cot2 求樹上兩點間路徑上有多少個不同的點權。序列上的莫隊是把詢問按照左端點分塊了 可是樹上沒有左端點,怎麼辦呢?我們把樹分塊...

模板 莫隊演算法

題意 給定乙個大小為n的陣列,陣列中所有元素的大小 n。你需要回答m個查詢。每個查詢的形式是l,r,k。你需要回答在範圍 l,r 中至少重複k次的數字的個數。n,m 100000 誒,這題卡了好久,tle,中間棄了一段,然後今天學弟學莫隊,拿出這個題,他也沒什麼想法,然後我頓時退一步海闊天空了。最開...

模板 莫隊演算法

這個演算法是由之前的國家隊隊長莫濤巨神 orz 發明的,所以尊稱莫隊演算法。如果我們知道區間 l,r 就能在o 1 求出 l 1,r l 1,r l,r 1 l,r 1 的話,那就可以用莫隊演算法了。1 排序,以左段點所在的塊為第一關鍵字,以右端點為第二關鍵字 2 從左往右處理詢問 離線 3 不斷調...