zoukankan      html  css  js  c++  java
  • 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
    ", ans[i]);
    
        return 0;
    }
  • 相关阅读:
    poj 1262 地板覆盖问题
    混合图 (Standard IO)
    matrix
    麻将 (Standard IO)
    C#多线程编程之:异步事件调用
    使用线程池与专用线程
    C#多线程编程之:Timer(定时器)使用示例
    C#多线程编程之:异步方法调用
    WCF 快速入门
    c#实现每隔一段时间执行代码(多线程)
  • 原文地址:https://www.cnblogs.com/zbtrs/p/5858030.html
Copyright © 2011-2022 走看看