bzoj1878 [SDOI2009]HH的项链

Posted zbtrs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj1878 [SDOI2009]HH的项链相关的知识,希望对你有一定的参考价值。

1878: [SDOI2009]HH的项链

Time Limit: 4 Sec  Memory Limit: 64 MB
Submit: 3199  Solved: 1611
[Submit][Status][Discuss]

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

分析:看到区间求数量,似乎可以用线段树解决,但是颜色的数量不能直接相加,故用线段树处理有些麻烦,如果不用线段树解决的话所有询问最好都是有序的,因此先按照左端点排序.

       如果我们询问区间[x,y],那么如果有一个颜色重复出现了多次,那么只需要计算一次即可,那么就要把区间内所有重复的颜色看成一个,具体是哪一个呢?因为要选一个特殊的点,那么一定要选一个特殊的位置,那么我们选择从左边出现的第一个,记为i,如果i的左边还有与i相同的颜色,那么一定在区间[x,y]之外,因为要求个数,那么就把区间[x,y]左边的颜色的下一个相同颜色的位置+1即可,因为是按照左端点排序的,所以不会重复计算,因为涉及到大量的区间计算,所以用到树状数组和前缀和,说的比较抽象,看一组数据:1 2 1 3,树状数组为:0 0 0 0,首先发现了第一个1,树状数组变成1 0 0 0,然后发现了2,变成了1 1 0 0,然后发现了1,变成了0 1 1 0,然后发现了3,变成0 1 1 1,对于一个询问[2,3],那么答案就是sum(3) - sum(2 - 1).那如果是求[1,1]呢?现在的答案是0!怎么办?其实根据之前的叙述,每次只需要考虑区间[x,y]左边的颜色即可,不好描述,如果不能理解请手动模拟几组数据就能找到规律了.

推荐一篇学习树状数组的博客:http://blog.csdn.net/int64ago/article/details/7429868

#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 50010, maxm = 200010, maxk = 1000010;

struct node
{
    int x, y, id;
}a[maxm];

int n,f[maxn],nextt[maxk],head[maxk],tempmax,s[maxn],m,ans[maxm];

bool cmp1(node p, node q)
{
    return p.x < q.x;
    if (p.x == q.x)
        return p.y < q.y;
}

void add(int x, int y)
{
    for (;x <= n; x += x&-x)
        s[x] += y;
}

int query(int x)
{
    int temp = 0;
    for (;x;x -= x&-x)
        temp += s[x];
    return temp;
}

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%d", &f[i]);
    for (int i = n; i >= 1; i--)
    {
        nextt[i] = head[f[i]];
        head[f[i]] = i;
        tempmax = max(tempmax, f[i]);
    }
    scanf("%d", &m);
    for (int i = 1; i <= m; i++)
    {
        scanf("%d%d", &a[i].x, &a[i].y);
        a[i].id = i;
    }
    sort(a + 1, a + 1 + m, cmp1);
    for (int i = 1; i <= tempmax; i++)
        if (head[i])
            add(head[i], 1);
    int cursor = 1;
    for (int i = 1; i <= m; i++)
    {
        while (cursor < a[i].x)
        {
            if (nextt[cursor])
                add(nextt[cursor], 1);
            cursor++;
        }
        ans[a[i].id] = query(a[i].y) - query(a[i].x - 1);
    }
    for (int i = 1; i <= m; i++)
        printf("%d\n", ans[i]);

    return 0;
}

 

以上是关于bzoj1878 [SDOI2009]HH的项链的主要内容,如果未能解决你的问题,请参考以下文章

[BZOJ1878][SDOI2009]HH的项链

BZOJ1878 [SDOI2009] HH的项链

BZOJ [1878[SDOI2009]HH的项链

[bzoj1878] [SDOI2009]HH的项链(树状数组+离线)

BZOJ1878: [SDOI2009]HH的项链[树状数组 离线]

BZOJ-1878: [SDOI2009]HH的项链(莫队算法)