数据结构题锦——树状数组

树状数组

SDOI2009]HH的项链

题目:

题目描述

HH 有一串由各种漂亮的贝壳组成的项链。HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH 不断地收集新的贝壳,因此,他的项链变得越来越长。

有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答…… 因为项链实在是太长了。于是,他只好求助睿智的你,来解决这个问题。

输入格式

一行一个正整数 nn,表示项链长度。
第二行 nn 个正整数 a_iai,表示项链中第 ii 个贝壳的种类。

第三行一个整数 mm,表示 HH 询问的个数。
接下来 mm 行,每行两个整数 l,rl,r,表示询问的区间。

输出格式

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

输入输出样例

输入 #1
6
1 2 3 4 3 5
3
1 2
3 5
2 6
输出 #1
2
2
4

说明/提示

【数据范围】

对于 20\%20% 的数据,1le n,mleq 50001n,m5000;
对于 40\%40% 的数据,1le n,mleq 10^51n,m105;
对于 60\%60% 的数据,1le n,mleq 5 imes 10^51n,m5×105;
对于 100\%100% 的数据,1le n,m,a_i leq 10^61n,m,ai106,1le l le r le n1lrn。

本题可能需要较快的读入方式,最大数据点读入数据约 20MB

分析:

这题本来是想用莫队来做的,结果,它卡我莫队,只好用树状数组来写。

这里的st数组使用来标记出现的值的下标的。

代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 1001115;
int n, m;
int w[N];
int tr[N], st[N];
int ans[N];
struct Query{
  int l, r, id;
  bool operator< (const Query &W) const{
    return r < W.r;
  }
}q[N];
inline int rd()
{
  int x = 0, f = 0; char c = getchar();
  while (!isdigit(c)) if (c == '-') f = 1, c = getchar();
  while (isdigit(c)) x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
  return f ? -x : x;
}
int lowbit(int x)
{
  return x & -x;
}
void add(int x, int c)
{
  for (; x <= n; x += lowbit(x)) tr[x] += c;
}
int ask(int x)
{
  int res = 0;
  for (; x; x -= lowbit(x)) res += tr[x];
  return res;
}
int main()
{
  // n = rd();
  scanf("%d", &n);
  for (int i = 1; i <= n; i ++ ) scanf("%d", &w[i]);
  // w[i] = rd();
  // m = rd();
  scanf("%d", &m);
  for (int i = 0; i < m; i ++ )
  {
    // int l = rd(), r = rd();
    int l,r; scanf("%d%d", &l, &r);
    q[i] = {l, r, i};
  }
  sort(q, q + m);
  for (int i = 0, j = 1; i < m; i ++ )
  {
    for (; j <= q[i].r; j ++ )
    {
      if (st[w[j]]) add(st[w[j]], -1);
      add(j, 1); st[w[j]] = j;
    }
    ans[q[i].id] = ask(q[i].r) - ask(q[i].l - 1);
  }
  for (int i = 0; i < m; i ++ ) printf("%d
", ans[i]);
  return 0;
}

  

原文地址:https://www.cnblogs.com/Iamcookieandyou/p/15057778.html