模板 莫隊 P3901 數列找不同

2022-07-11 14:21:08 字數 4056 閱讀 6339

目錄**

[模板]莫隊/p3901 數列找不同

傳送門沒有專門的模板,就把這道題作為模板啦

聽說這題有o(n)預處理,o(1)詢問的方法,但是這不重要,還是先練練莫隊吧

《演算法競賽 高階指南》裡面沒有專門講莫隊,學得就有一丟丟麻煩

簡單說,莫隊就是

優雅的暴力

首先要注意:

莫隊是離線演算法

我們把詢問分成t塊(不一定十分精確,可能多出或缺少幾個塊,只是借用了分塊的思想),任意乙個塊內,每乙個詢問的左端點和其它詢問的左端點的差的絕對值不超過\(\sqrt n\),且塊內右端點公升序排列.所以就有了進行stl sort的cmp函式:

bool cmp(node a , node b) 

//在主函式中:t=sqrt(n)

t到這裡就被已經拋棄了(毫無存在感)

對於排序後的每乙個詢問,我們抹去上乙個詢問的多出來的答案,並補充上乙個詢問沒有的部分,得到當前詢問的答案,為了方便,一般寫成兩個函式:

void add(int l , int r) 

}void earse(int l , int r)

}

莫隊到這裡就介紹完了,接下來看看時間複雜度:

很顯然,時間主要是花在了對詢問的處理上,所以我們只討論詢問處理部分

分兩種情況:

分塊的第乙個詢問:由於塊和塊之間沒有比較大的約定,addearse兩個操作都有可能要用到\(o(n)\)的時間,又因為有\(\sqrt n\)個塊,所以時間複雜度為\(o(n\sqrt n)\)

其它情況:由於每乙個塊內右端點是遞增的,所以乙個塊對右端點的處理總共用時\(o(n)\),又因為一共有\(\sqrt n\)個塊,所以處理右端點總共用時\(o(n\sqrt n)\).對於左端點,由於分塊內的左端點之差不超過\(\sqrt n\),所以處理所有詢問的左端點共用時\(o(n\sqrt n)\)

(這裡不單獨討論每乙個塊是因為塊的長度不定,不如全部一起討論更容易理解)

綜上,時間複雜度為\(o(n\sqrt n)\)

#include #include #include #include #define nn 100010

using namespace std;

int read()

struct nodeask[nn];

int t;

bool cmp(node a , node b)

int vis[nn];

int n , q;

int a[nn];

int check;

bool ans[nn];

void add(int l , int r)

}void earse(int l , int r)

}int main()

t = sqrt(n);

sort(ask + 1 , ask + q + 1 , cmp);

// cout << endl;

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

// cout << ask[i].l << ' ' << ask[i].r << endl;

// return 0;

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

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

puts(ans[i] ? "yes" : "no");

return 0;

}

#include #include #include #include #define nn 100010

using namespace std;

int read()

struct nodeask[nn];

int t;

bool cmp(node a , node b)

int vis[nn];

int n , q;

int a[nn];

int check;

bool ans[nn];

void add(int l , int r)

}void earse(int l , int r)

}int main()

t = sqrt(n);

sort(ask + 1 , ask + q + 1 , cmp);

// cout << endl;

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

// cout << ask[i].l << ' ' << ask[i].r << endl;

// return 0;

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

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

puts(ans[i] ? "yes" : "no");

return 0;

}

#include using namespace std;

int main()

puts("tested2");

t = clock() - t;

printf(">time: %d\n" , t);

if(t >= 1500)

continue;

system("std.exe < input.txt > output2.txt");

puts("std");

if(system("fc output1.txt output2.txt"))

} system("start input.txt");

return 0;

}

#include #include #include #include #include #define nn 100010

using namespace std;

int read()

int vis[nn];

int a[nn];

int n , q;

int main()

return 0;

}

#include #include #include #include #include #define nn 100010

using namespace std;

int read()

int vis[nn];

int a[nn];

int n , q;

struct querynode ask[nn];

bool cmp0(querynode a , querynode b)

bool cmp1(querynode a , querynode b)

int ans[nn];

int t;

int l[110] , r[110];

int main()

ans[ask[l[i]].id] = (check == 0 ? true : false);

for(int j = l[i] + 1 ; j <= r[i] ; j++)

else

for(int k = ask[j].l ; k < ask[j - 1].l ; k++)

for(int k = ask[j - 1].r + 1 ; k <= ask[j].r ; k++)

/*check = 0;

for(int k = ask[j].l ; k <= ask[j].r ; k++)

if(vis[a[k]] > 1)

check++;*/

ans[ask[j].id] = (check == 0 ? true : false);

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

puts(ans[i] ? "yes" : "no");

return 0;

}

莫隊 P3901 數列找不同

現有數列a 1,a 2,cdots,a na1 a2 an q 個詢問 l i,r i li ri a a cdots,a ali ali 1 ari 是否互不相同 輸入格式 第1 行,2 個整數n,qn,q 第2 行,n 個整數a a cdots,a ali ali 1 ari q 行,每行2 個...

P3901 數列找不同(簡單莫隊)

莫隊入門題目,區間不相同數查詢 應該用線段樹也能做,但是不知道該維護什麼。一篇很好的題解 莫隊演算法主要解決的問題 莫隊演算法是用來處理一類無修改的離線區間詢問問題。莫隊演算法的思想 1 分塊and排序,使相鄰的查詢區間盡量接近,curl和curr兩個指標移動的距離盡量少 2 桶排查找 1 incl...

洛谷 P3901 數列找不同 莫隊

題目描述 現有數列 a1,a2,a na 1,a 2,ldots,a n a1 a2 an q qq 個詢問 li ri l i,r i li r i 詢問 ali ali 1,ari a a ldots,a ali ali 1 ar i 是否互不相同。輸入格式 第一行,兩個整數 n,q n,qn,...