原题链接
思路:
原本是一个莫队的模板题,
数据加强后 1e6 的数据范围显然莫队是过不去了.
将询问按 r 排序,
然后考虑从左往右扫描所有询问.
从左往右扫描时,对于某个数,
只需要考虑其最右出现的位置.
可以使用一个树状数组维护位置信息.
若当前位置的数是最右位置的数则置为 1, 否则置为 0. 这样 sum (r) -
sum (l-1) 便是询问的答案.
代码:
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
| #include <cstdio> #include <cctype> #include <algorithm> using namespace std; const int Mn(1000500); template<typename T> void qrd(T& x) { x = 0; int c = getchar(); while(!isdigit(c)) { c = getchar(); } while(isdigit(c)) { x = x*10 + c-'0'; c = getchar(); } } template<typename T, typename... Ts> void qrd(T& x, Ts&... xs) { qrd(x); qrd(xs...); }
int n; int arr[Mn], c[Mn], aps[Mn]; struct qrd { int l, r, id; bool operator < (const qrd& rhs) const { return r<rhs.r; } }aq[Mn]; int ans[Mn];
inline int lb(const int& x) { return x&-x; } void mdf(int p,int mx) { for(; p<=n; p+=lb(p)) { c[p] += mx; } } int sum(int p) { int ret(0); for(; p; p-=lb(p)) { ret += c[p]; } return ret; }
int main() { qrd(n); for(int i(1);i<=n;++i) { qrd(arr[i]); } int m; qrd(m); for(int i(1);i<=m;++i) { qrd(aq[i].l, aq[i].r); aq[i].id = i; } sort(aq+1,aq+m+1); for(int i(1), p(1); i<=n; ++i) { if(aps[arr[i]]) { mdf(aps[arr[i]],-1); } aps[arr[i]] = i; mdf(i,1); while(p<=m && aq[p].r==i) { ans[aq[p].id] = sum(aq[p].r) - sum(aq[p].l-1); ++p; } } for(int i(1);i<=m;++i) { printf("%d\n",ans[i]); } return 0; }
|