• 线段树或树状数组---Flowers


    题目网址:http://acm.hdu.edu.cn/showproblem.php?pid=4325

    Description

    As is known to all, the blooming time and duration varies between different kinds of flowers. Now there is a garden planted full of flowers. The gardener wants to know how many flowers will bloom in the garden in a specific time. But there are too many flowers in the garden, so he wants you to help him.
     

    Input

    The first line contains a single integer t (1 <= t <= 10), the number of test cases. 
    For each case, the first line contains two integer N and M, where N (1 <= N <= 10^5) is the number of flowers, and M (1 <= M <= 10^5) is the query times. 
    In the next N lines, each line contains two integer S i and T i (1 <= S i <= T i <= 10^9), means i-th flower will be blooming at time [S i, Ti]. 
    In the next M lines, each line contains an integer T i, means the time of i-th query. 
     

    Output

    For each case, output the case number as shown and then print M lines. Each line contains an integer, meaning the number of blooming flowers. 
    Sample outputs are available for more details. 
     

    Sample Input

    2 1 1 5 10 4 2 3 1 4 4 8 1 4 6
     

    Sample Output

    Case #1:
    0
    Case #2:
    1
    2
    1
     

    题意:有n种花,给了这n种花的花期时间,Si~Ti,求在某一时间t,有多少种花正在开放。

    思路:这题给的花期时间数据为1~10^9,无法开辟这么大的数组,不能直接建树,必须先将数据进行离散化。离散化:在百科上看到一句很好的话:“离散化就是把连续的量,变成离散的量即变成一个一个的值”,例如区间(1,100)由于这是一个实数区间,其中间的值有无数个,如果我们能把它变为1到100内的整数,这样这些数就变成了有限个,即离散了;  ,们将每个区间的端点都存到一个数组中,然后将这些端点,按照从小到大排列(之后要去除这个数组中重复的点),并建立为与其下标的映射,然后用其下标建树,因为我们只是使用了需要的空间,并没有在整个空间上建树,这样就大大节省了空间和时间,如题中第二个例子,我们将所有数据按照从小到大排列后为1 2 3 4 6 8 分别对应下标1 2 3 4 5 6,此题数据小我们看不出明显的差别,但是如果数据中有区间(1000,10000),那差别马上就出来了,比如我们把题中的区间(4,8)换做(1000,10000)那么如果采用离散化思想,我们还是先排列大小 1 2 3 6 1000 10000对应下标1 2 3 4 5 6,我们只需建一棵根为6的树即可,如果不用离散化,我们就需要建造根为10000的树,大大浪费了空间。

    然而!!!我发现同学他们的代码没有使用离散化,而是开辟了150000的空间就过了,很明显测试数据没有很大,都在150000以内,唉!所以可以不用离散化。

    方法一:使用树状数组,若花期为t1~t2,更新t1-1及t1-1以下的子树根节点都减一,更新t2及t2以下的子树根节点加一,若求x时刻有多少种花正开着,将x及上方一路节点均相加,最后的和即是结果。

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #define N 152005
    using namespace std;
    int c[N];
    
    int Lowbit(int t)
    {   ///设k为t末尾0的个数,则求得为2^k=t&(t^(t-1));
        return t&(t^(t-1));
    }
    void update(int x,int t)
    {
        while(x > 0)
        {
            c[x]+=t;
            x -= Lowbit(x);
        }
    }
    int sum(int li)
    {
        int sum=0;
        while(li<=N)
        {
            sum+=c[li];
            li=li+Lowbit(li);
        }
        return sum;
    }
    
    int main()
    {
        int T;
        int n,M,t1,t2,x,Case=1;
        scanf("%d",&T);
        while(T--)
        {
            memset(c,0,sizeof(c));
            scanf("%d%d",&n,&M);
            while(n--)
            {
                scanf("%d%d",&t1,&t2);
                update(t1-1,-1);
                update(t2,1);
            }
            printf("Case #%d:
    ",Case++);
            while(M--)
            {
                scanf("%d",&x);
                printf("%d
    ",sum(x));
            }
        }
        return 0;
    }

    方法二:使用线段树进行区间更新。

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    const int Max=150005;
    int N,M;
    int c[Max];
    
    struct Node
    {
        int l,r;
        int cnt;
    }node[5*Max];
    
    void build(int L,int R,int i)
    {
        node[i].l=L;
        node[i].r=R;
        node[i].cnt=0;
        if(L==R)  return;
        int mid=(L+R)/2;
        build(L,mid,2*i);
        build(mid+1,R,2*i+1);
    }
    
    int update(int t1,int t2,int i)
    {
        if(node[i].l==t1&&node[i].r==t2)
        {
            node[i].cnt++;
            return 0;
        }
        int mid=(node[i].l+node[i].r)/2;
        if(t2<=mid) update(t1,t2,2*i);
        else if(t1>mid)  update(t1,t2,2*i+1);
        else
        {
            update(t1,mid,2*i);
            update(mid+1,t2,2*i+1);
        }
    }
    
    int chazhao(int x,int i)
    {
        int sum=0;
        if(node[i].l<=x&&node[i].r>=x)
            sum+=node[i].cnt;
        if(node[i].l>x) return 0;
        if(node[i].r<x) return 0;
        sum+=chazhao(x,2*i);
        sum+=chazhao(x,2*i+1);
        return sum;
    }
    
    int main()
    {
        int T,t1,t2,Case=1;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d",&N,&M);
            build(1,Max,1);
            for(int i=1;i<=N;i++)
            {
                scanf("%d%d",&t1,&t2);
                update(t1,t2,1);
            }
            for(int i=0;i<M;i++)
            scanf("%d",&c[i]);
            printf("Case #%d:
    ",Case++);
            for(int i=0;i<M;i++)
            {
                printf("%d
    ",chazhao(c[i],1));
            }
        }
        return 0;
    }
  • 相关阅读:
    UVA1401 Remember the word DP+Trie
    LG5202 「USACO2019JAN」Redistricting 动态规划+堆/单调队列优化
    模拟赛总结合集
    LG5201 「USACO2019JAN」Shortcut 最短路树
    LG5200 「USACO2019JAN」Sleepy Cow Sorting 树状数组
    LG5196 「USACO2019JAN」Cow Poetry 背包+乘法原理
    20190922 「HZOJ NOIP2019 Round #7」20190922模拟
    LG2530 「SHOI2001」化工厂装箱员 高维DP+记忆化搜索
    LG2893/POJ3666 「USACO2008FEB」Making the Grade 线性DP+决策集优化
    关于对QQ 输入法的评价
  • 原文地址:https://www.cnblogs.com/chen9510/p/5326794.html
Copyright © 2020-2023  润新知