题目
啊 被牛客题目描述坑了,把关键信息藏在数据范围里,不过顺便学了一下莫队。
牛客题目https://ac.nowcoder.com/acm/contest/7079/A , 知道真实题意以后是个水题
大意
指莫队要解决的问题不是牛客的题。
给长n的数组,没有改动,q次询问区间的不同值的个数
q和n都1e5
解法
我看到mex都很慌,这玩意虽然看上去是个质朴的东西,但涉及到的都不太好搞
上面 直接暴力,就 O(q n)。
莫队实际上就是 优雅的分块,然后再暴力。
- 离线请求。
- 根据请求的
[左端点/sqrt(n), 右端点]
排序
- 暴力求解
意味着,每次对于 左端点/sqrt(n)
相同的时候, 时间复杂度= sqrt(n)*询问个数 + n
总时间复杂度 sqrt(n)*q + n*sqrt(n)
一些优化,通过奇偶 来决定右端点是 正序还是逆序列。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| #include <bits/stdc++.h> using namespace std;
typedef long long ll; #define ten5 100000+10 #define rep(i,a,n) for (int i=a;i<n;i++) #define iif(c,t,f) ((c)?(t):(f)) #define per(i,a,n) for (int i=n-1;i>=a;i--)
const int MAXN = 30005; const int MAXQ = 200005; const int MAXM = 1000005;
int sq; struct query{ int l, r, id; bool operator<(const query &o) const { if (l / sq != o.l / sq) return l < o.l; if (l / sq & 1) return r < o.r; return r > o.r; } } Q[MAXQ]; int A[MAXN]; int ans[MAXQ]; int Cnt[MAXM]; int cur; int l = 1, r = 0;
void add(int p) { if (Cnt[A[p]] == 0) cur++; Cnt[A[p]]++; } void del(int p) { Cnt[A[p]]--; if (Cnt[A[p]] == 0) cur--; } ll read(){ ll r; scanf("%lld",&r); return r; } int main() { int n = read(); sq = sqrt(n); rep(i,1,n+1){ A[i] = read(); } int q = read(); rep(i,0,q){ Q[i].l = read(); Q[i].r = read(); Q[i].id = i; } sort(Q, Q + q); rep(i,0,q){ while (l < Q[i].l) del(l++); while (l > Q[i].l) add(--l); while (r < Q[i].r) add(++r); while (r > Q[i].r) del(r--); ans[Q[i].id] = cur; } rep(i,0,q){ printf("%d\n", ans[i]); } return 0; }
|
参考
各种莫队博文