Address
Solution
- 题目大意:多次询问区间 [l,r] [ l , r ] 有多少个次数 ≥2 ≥ 2 的数。
- 先考虑一种暴力,记 suf[i] s u f [ i ] 表示与位置 i i 颜色相同的下一个位置。
- 对于询问 ,对于每种颜色我们暴力找到满足 l≤suf[i]<suf[suf[i]]≤r l ≤ s u f [ i ] < s u f [ s u f [ i ] ] ≤ r 的最小 i i ,则把这种颜色加入答案。
- 我们会发现暴力多次重复找了相同的位置。
- 因此对 个询问按 l l 从小到大排序,用一个树状数组维护区间和。
- 有序,通过不断右移的指针 i(i<l) i ( i < l ) 来模拟暴力找的过程。
- 考虑将位置
i
i
移除对结果产生的影响:
- 如果有 ,则位置 suf[i] s u f [ i ] 之前已经被标记过了,因为出现次数要 ≥2 ≥ 2 ,我们当前 i i 这个位置上的数已经不包括在询问的区间中了,所以 肯定不是出现次数 ≥2 ≥ 2 的数的最后那一个,标记为0。
- 如果有 suf[suf[i]] s u f [ s u f [ i ] ] ,则将位置 suf[suf[i]] s u f [ s u f [ i ] ] 标记为1。
- 询问时即用树状数组求区间和,时间复杂度 O(nlogn) O ( n log n ) 。
Code
#include <iostream> #include <cstdio> #include <cctype> #include <algorithm> #include <cstring> using namespace std; namespace inout { const int S = 1 << 20; char frd[S], *ihed = frd + S; const char *ital = ihed; inline char inChar() { if (ihed == ital) fread(frd, 1, S, stdin), ihed = frd; return *ihed++; } inline int get() { char ch; int res = 0; bool flag = false; while (!isdigit(ch = inChar()) && ch != '-'); (ch == '-' ? flag = true : res = ch ^ 48); while (isdigit(ch = inChar())) res = res * 10 + ch - 48; return flag ? -res : res; } char fwt[S], *ohed = fwt; const char *otal = ohed + S; inline char outChar(char ch) { if (ohed == otal) fwrite(fwt, 1, S, stdout), ohed = fwt; return *ohed++ = ch; } inline void put(int x) { if (x > 9) put(x / 10); outChar(x % 10 + 48); } }; using namespace inout; const int N = 2e6 + 5; int n, C, m; int suf[N], low[N], a[N], b[N], c[N], Ans[N]; struct node { int l, r, z; bool operator < (const node &x) const { return l < x.l; } }p[N]; inline void Modify(int x, int y) { for (; x <= n; x += low[x]) b[x] += y; } inline int Query(int x) { int res = 0; for (; x; x ^= low[x]) res += b[x]; return res; } int main() { // freopen("flower.in", "r", stdin); // freopen("flower.out", "w", stdout); n = get(); C = get(); m = get(); for (int i = 1; i <= n; ++i) a[i] = get(), low[i] = i & -i; for (int i = n; i >= 1; --i) suf[i] = c[a[i]], c[a[i]] = i; for (int i = 1; i <= m; ++i) p[i].l = get(), p[i].r = get(), p[i].z = i; sort(p + 1, p + m + 1); for (int i = 1; i <= C; ++i) if (c[i] && suf[c[i]]) Modify(suf[c[i]], 1); int j = 1; for (int i = 1; i <= m; ++i) { for (; j < p[i].l; ++j) { if (suf[j]) Modify(suf[j], -1); if (suf[j] && suf[suf[j]]) Modify(suf[suf[j]], 1); } Ans[p[i].z] = Query(p[i].r) - Query(p[i].l - 1); } for (int i = 1; i <= m; ++i) put(Ans[i]), outChar('\n'); fwrite(fwt, 1, ohed - fwt, stdout); // fclose(stdin); fclose(stdout); return 0; }