• SDOI 2009 HH的项链


    题目描述 Description

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

    输入描述 Input Description

    第一行:一个整数N,表示项链的长度。

    第二行:N个整数,表示依次表示项链中贝壳的编号(编号为0到1000000之间的整数)。

    第三行:一个整数M,表示HH询问的个数。

    接下来M行:每行两个整数,L和R(1 ≤ L ≤ R ≤ N),表示询问的区间。

    输出描述 Output Description

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

    样例输入 Sample Input

    6

    1 2 3 4 3 5

    3

    1 2

    3 5

    2 6

    样例输出 Sample Output

    2

    2

    4

    数据范围及提示 Data Size & Hint

    对于20%的数据,N ≤ 100,M ≤ 1000;

    对于40%的数据,N ≤ 3000,M ≤ 200000;

    对于100%的数据,N ≤ 50000,M ≤ 200000。

      真心是蒟蒻,看答案都看了半天。最后写的时候还忘记了数据被我排序处理过。

      首先,这个题目要用离线算法,也就是把所有数据都读入进来后,在进行运算。我们将需要查找的区间按右端点升序排列起来(左端点顺序无所谓)。

      接下来,我们用树状数组来解决剩下的问题。

      我们从第一颗珠子开始,逐个扫描,如果该类珠子是第一次出现,那么我们就记录下他的位置;如果他出现之前还有同类珠子出现,那我们就把他前面的那一个珠子去掉,然后记录下这颗珠子的位置。在树状数组中,每扫描到一个珠子,都要进行一次ADD(1)的操作。去掉珠子就需要找到要去的珠子的位置,然后在线段树上执行ADD(-1)的操作。

      在扫描珠子的同时,我们不断的判断离散化后的区间,如果当前判断的区间的右端点恰为我们扫描到的珠子,那么他的答案也就是 SUM(R)-SUM(L-1)。

      务必要保证扫描珠子和判断区间同时进行。先扫描珠子,那么在判断区间时,SUM(R)和SUM(L-1),有可能被执行过ADD(-1)操作,也就是说求得的数据可能小于正确答案。

    代码如下

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 
     5 int l[200002], r[200002], n, m, a[50001], pre[1000001], c[50001], z[200002], ans[200002];
     6 
     7 
     8 void qsort(int s, int t) {                //排序
     9     int i = s, j = t, x = r[(s+t)/2];
    10     while (i < j) {
    11         while (r[i] < x) i++;
    12         while (r[j] > x) j--;
    13         if (i <= j) {
    14             int k = r[i];
    15             r[i] = r[j];
    16             r[j] = k;
    17             k = l[i];
    18             l[i] = l[j];
    19             l[j] = k;
    20             k = z[i];
    21             z[i] = z[j];
    22             z[j] = k;
    23             i++;
    24             j--;
    25         }
    26     }
    27     if (s < j) qsort(s, j);
    28     if (i < t) qsort(i, t);
    29 }
    30 
    31 int lowbit(int x) {          //lowbit函数
    32     return x&-x;
    33 }
    34 
    35 int sum(int x) {          //求前缀和
    36     int sum1 = 0;
    37     while (x > 0) {
    38         sum1 += c[x]; x -= lowbit(x);
    39     }
    40     return sum1;
    41 }
    42 
    43 void add(int x, int k) {      //改值
    44     while (x <= n) {
    45         c[x] += k; x += lowbit(x);
    46     }
    47 }
    48 
    49 int main() {
    50     ios::sync_with_stdio(false);
    51     scanf("%d", &n);
    52     for (int i = 1; i <= n; i++)
    53         scanf("%d", &a[i]);
    54     scanf("%d", &m);
    55     for (int i = 1; i <= m; i++) {
    56         scanf("%d%d", &l[i], &r[i]);
    57         z[i] = i;    
    58     }
    59     qsort(1, m);
    60     int p = 1, q = 1;     //p为当前区间,q为当前珠子
    61     while (p <= m) {
    62         int tail = r[p];
    63         while (q <= tail) {
    64             add(q, 1);
    65             if (pre[a[q]] != 0)   //被搜索过
    66                 add(pre[a[q]], -1);
    67             pre[a[q]] = q;
    68             q++;
    69         }
    70         while (r[p] == tail) {
    71             ans[z[p]] = sum(r[p]) - sum(l[p] - 1);  //把答案放入原先对应位置
    72             p++;
    73         }
    74     }
    75     for (int i = 1; i <= m; i++) 
    76         cout << ans[i] << "
    ";
    77     return 0;
    78 }
  • 相关阅读:
    Devexpress [汇总链接]
    [转]修改LayoutControlitem容器内的控件长宽
    How to hide border of XtraTabControl
    CEF / Chromium 重新编译2018 官网地址 一路是坑 千万别跟着官方step by step走一定多思考多查资料 因为改动地方太多了编译都每个版本都不一样
    c#:配置引用程序集的路径(分离exe和dll)和 如何处理[dllImport]中的程序集的加载 [笔记]
    [redis] -- 缓存雪崩和缓存穿透、缓存击穿问题解决方案篇
    [redis] -- 为什么那么快
    [redis] -- 集群篇
    [spring cloud] -- 服务注册与服务发现篇
    [spring cloud] -- 核心篇
  • 原文地址:https://www.cnblogs.com/xstsow/p/4408995.html
Copyright © 2020-2023  润新知