一、题意概述
给你 n (1≤n≤105) n ( 1 ≤ n ≤ 10 5 ) 个数 a1...n (1≤ai≤n) a 1... n ( 1 ≤ a i ≤ n ) 并且有 q (1≤q≤105) q ( 1 ≤ q ≤ 10 5 ) 次询问,每次询问给出 li,ri l i , r i 问你由 {a1,a2..al−1,al,ar,ar+1..an} { a 1 , a 2 . . a l − 1 , a l , a r , a r + 1 . . a n } 这些数组成的新序列,有多少个不同的数?
二、解题思路
考虑维护每个元素
x
x
的第一次出现位置和最后一次出现位置 first[x]
和 last[x]
,预处理出所有序列的元素,离线按照 从小到大排序,每次维护那些没有出现的数,假设
r=last[x]
r
=
l
a
s
t
[
x
]
,那么当
l<first[x]
l
<
f
i
r
s
t
[
x
]
的时候这个数
x
x
,没有出现。排序以后从大到小枚举 ,用树状数组维护每次的答案。
一开始的
O(nn−−√)
O
(
n
n
)
的分块想法 Time Limited Exceed
了,卡得挺死。
三、解题代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int c[maxn], n, m;
inline int lowbit(int x) { return x & (-x); }
inline void modify(int i, int v) {
while (i <= n) {
c[i] += v;
i += lowbit(i);
}
}
inline int query(int i) {
int res = 0;
while (i > 0) {
res += c[i];
i -= lowbit(i);
}
return res;
}
int first[maxn], last[maxn];
struct Query {
int l, r, id, ans;
} q[maxn];
int a[maxn];
inline bool cmp1(const Query& x, const Query& y) { return x.r < y.r || (x.r == y.r && x.l < y.l); }
inline bool cmp2(const Query& x, const Query& y) { return x.id < y.id; }
int main() {
while (~scanf("%d%d", &n, &m)) {
memset(first, -1, sizeof first);
memset(c, 0, sizeof c);
int all = 0;
for (int i=1; i<=n; i++) {
scanf("%d", &a[i]);
if (first[a[i]] == -1) first[a[i]] = i, all++;
last[a[i]] = i;
}
for (int i=1; i<=m; i++) {
scanf("%d%d", &q[i].l, &q[i].r);
q[i].id = i;
}
sort(q+1, q+m+1, cmp1);
int now = 1;
for (int i=1; i<=n; i++) {
while (now <= m && q[now].r == i) {
q[now].ans = all - query(n) + query(q[now].l);
now++;
}
if (last[a[i]] == i) modify(first[a[i]], 1);
}
sort(q+1, q+m+1, cmp2);
for (int i=1; i<=m; i++) printf("%d\n", q[i].ans);
}
return 0;
}