[BZOJ1878] [SDOI2009] HH的项链 (树状数组)

时间:2023-01-03 04:26:47

Description

  HH有一串由各种漂亮的贝壳组成的项链。HH相信不同的贝壳会带来好运,所以每次散步 完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH不断地收集新的贝壳,因此, 他的项链变得越来越长。有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同 的贝壳?这个问题很难回答。。。因为项链实在是太长了。于是,他只好求助睿智的你,来解 决这个问题。

Input

  第一行:一个整数N,表示项链的长度。 第二行:N个整数,表示依次表示项链中贝壳的编号(编号为0到1000000之间的整数)。 第三行:一个整数M,表示HH询问的个数。 接下来M行:每行两个整数,L和R(1 ≤ L ≤ R ≤ N),表示询问的区间。

Output

  M行,每行一个整数,依次表示询问对应的答案。

Sample Input

6
1 2 3 4 3 5
3
1 2
3 5
2 6

Sample Output

2
2
4

HINT

  对于20%的数据,N ≤ 100,M ≤ 1000;
  对于40%的数据,N ≤ 3000,M ≤ 200000;
  对于100%的数据,N ≤ 50000,M ≤ 200000。

Source

  Day2

Solution

  挺经典的一道题。

  大体思路是:对于每一个询问区间[l, r],我们只需关注[l, n]中第一次出现的颜色的位置,把答案+1

  nxt[i]存储颜色a[i]的下一个位置在哪,把每一种颜色的第一次出现的位置的答案+1,举例如下:

  a[i]:    1   4   4   2   3   4   3   3   1   2

  ans[i]: 1   1   0   1   1   0   0   0   0   0

  把询问操作按左端点排序,假如现在要执行询问[2, 4],那么ans[1]信息已失效,把a[i]的下一个对应位置更新

  nxt[1] = 9

  a[i]:    1   4   4   2   3   4   3   3   1   2

  ans[i]: 1   1   0   1   1   0   0   0   1   0

  答案就是1 + 0 + 1 = 2

  再加入又要执行询问[6, 9],先更新[2, 5]的下一个的信息(因为a[1]已更新)

  nxt[2] = 3, nxt[3] = 6, nxt[4] = 10, nxt[5] = 7:

  a[i]:    1   4   4   2   3   4   3   3   1   2

  ans[i]: 1   1   1   1   1   1   1   0   1   1

  答案就是1 + 1 + 0 + 1 = 3,以此类推。

  注意到这个方法可以保证每一种颜色在区间内只在第一次出现时被算过一遍。

  复杂度是O(n^2),需用树状数组维护前缀和使复杂度降为O(nlogn)

 #include <bits/stdc++.h>
using namespace std;
struct query
{
int id, l, r, ans;
}q[];
int n, a[], fst[], nxt[], BIT[], ctot; bool cmp1(const query &lhs, const query &rhs)
{
return lhs.l == rhs.l ? lhs.r < rhs.r : lhs.l < rhs.l;
} bool cmp2(const query &lhs, const query &rhs)
{
return lhs.id < rhs.id;
} void update(int x, int val)
{
for(; x <= n; x += x & -x)
BIT[x] += val;
} int query(int x)
{
int ans = ;
for(; x; x -= x & -x)
ans += BIT[x];
return ans;
} int main()
{
int m, l = ;
scanf("%d", &n);
for(int i = ; i <= n; i++)
scanf("%d", a + i), ctot = max(ctot, a[i]);
for(int i = n; i; i--)
nxt[i] = fst[a[i]], fst[a[i]] = i;
for(int i = ; i <= ctot; i++)
if(fst[i]) update(fst[i], );
scanf("%d", &m);
for(int i = ; i <= m; i++)
scanf("%d%d", &q[i].l, &q[i].r), q[i].id = i;
sort(q + , q + m + , cmp1);
for(int i = ; i <= m; i++)
{
while(l < q[i].l - )
if(nxt[++l]) update(nxt[l], );
q[i].ans = query(q[i].r) - query(q[i].l - );
}
sort(q + , q + m + , cmp2);
for(int i = ; i <= m; i++)
printf("%d\n", q[i].ans);
return ;
}