---
# System prepended metadata

title: 莫隊

---

# 莫隊

* 主要想法：如果知道[a,b]的答案，那也可以$O(1)$的時間知道[a+1,b], [a-1, b], [a, b+1], [a, b-1]的答案，因此也是離線算法
* 但是如果指針不停的來回，複雜度扔是$O(n)$，因此重點是要盡量減少指針來回的次數
    * 利用分塊法的想法，如果把區間每$\sqrt n$分成一塊，這樣一次查詢複雜度就是$O(\sqrt n)$
    * 因此先把左界照分塊排序，左界分塊相同的照右界大小排序，離線複雜度是$O(n\sqrt q)$

:::info
跟直接對左界大小排序有什麼差別？
考慮這樣的查詢：
1, 1000000
2, 2
3, 1000000
4, 2
右指針走法會是1->1000000->2->1000000->2，複雜度很慘

但用莫對查詢順序會變：
2, 2
1, 1000000
4, 2
3, 1000000
而右指針走法會變1->2->1000000->2->1000000，顯然少來回了幾次
所以莫對只是一個折衷
:::

區間眾數
---
```cpp=
#include <bits/stdc++.h>
#define EB emplace_back
#define vci vector<int>
#define PII pair<int,int>
#define F first
#define S second
#define rep(X, a,b) for(int X=a;X<b;++X)
#define ALL(a) (a).begin(), (a).end()
#define SZ(a) (int)(a).size()
#define NL "\n"
#define LL long long

using namespace std;

LL l=1, r=1, ans=1, K;
LL cnt[100010]={0}, num[100010], cntcnt[100010]={0};

struct qy{
	LL l, r, id;
	bool operator<(const qy& q){
		return l/K==q.l/K?r<q.r:l/K<q.l/K;
	}
};

void add(LL a){
	cntcnt[cnt[a]]--;
	cnt[a]++;
	cntcnt[cnt[a]]++;
	ans=max(ans, cnt[a]);
}

void sub(LL a){
	cntcnt[cnt[a]]--;
	cnt[a]--;
	cntcnt[cnt[a]]++;
	if(cnt[a]+1==ans && cntcnt[cnt[a]+1]==0) ans=cnt[a];
}

int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    LL n, m;
    cin>>n>>m;
    K=sqrt(n);
    
    vector<qy> qry(m);
    rep(i,1,n+1) cin>>num[i];
    rep(i,0,m){
        cin>>qry[i].l>>qry[i].r;
        qry[i].id=i;
    }
    sort(ALL(qry));
    vector<pair<LL,LL>> res(m);
    
    cnt[num[1]]=1;
    cntcnt[1]=1;
    for(auto a:qry){
        while(l<a.l) sub(num[l++]);
        while(l>a.l) add(num[--l]);
        while(r<a.r) add(num[++r]);
        while(r>a.r) sub(num[r--]);
        res[a.id]={ans, cntcnt[ans]};
    }
	for(auto a:res) cout<<a.F<<" "<<a.S<<NL;
}
```