zoukankan      html  css  js  c++  java
  • hdoj 4325 Flowers【线段树+离散化】

    Flowers

    Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
    Total Submission(s): 2616    Accepted Submission(s): 1287


    Problem 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 Si and Ti (1 <= Si <= Ti <= 10^9), means i-th flower will be blooming at time [Si, Ti].
    In the next M lines, each line contains an integer Ti, 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以及m个要查询的时间,接下来n行是每种花的开放区间(其中一些花的开放区间有重合的部分),接下来m个数非别表示要查询的点(查询在这个时间点,有多少种花开放)
     
    题解:直接线段树建图的话由于数据达到了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的树,大大浪费了空间,
     
    AC代码:
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define LL long long
    #define MAX 100100
    using namespace std;
    int s[MAX],e[MAX],q[MAX];
    int rec[MAX];//记录所有值排序后的下标 
    int add[MAX<<2];
    int sum[MAX<<2];
    int le[MAX],ri[MAX];
    void pushup(int o)
    {
        sum[o]=sum[o<<1]+sum[o<<1|1];
    }
    void pushdown(int o,int m)
    {
        if(add[o])
        {
            add[o<<1]+=add[o];
            add[o<<1|1]+=add[o];
            sum[o<<1]+=add[o]*(m-(m>>1));
            sum[o<<1|1]+=add[o]*(m>>1);
            add[o]=0;
        }
    }
    void gettree(int o,int l,int r)
    {
        add[o]=0;
        if(l==r)
        {
            sum[o]=0;
            return ;
        }
        int mid=(l+r)>>1;
        gettree(o<<1,l,mid);
        gettree(o<<1|1,mid+1,r);
        pushup(o);
    }
    void update(int o,int l,int r,int L,int R,int val)
    {
        if(L<=l&&R>=r)
        {
            add[o]+=val;
            sum[o]+=val*(r-l+1);
            return ;
        }
        pushdown(o,r-l+1);
        int mid=(l+r)>>1;
        if(L<=mid)
            update(o<<1,l,mid,L,R,val);
        if(R>mid)
            update(o<<1|1,mid+1,r,L,R,val);
        pushup(o);
    }
    int find(int o,int l,int r,int pos)
    {
        if(l==r)
        {
            return sum[o];
        }
        pushdown(o,r-l+1);
        int ans=0;
        int mid=(l+r)>>1;
        if(pos<=mid)
            ans=find(o<<1,l,mid,pos);
        else
            ans=find(o<<1|1,mid+1,r,pos);
        return ans;
    }
    int query(int l,int r,int pos)//查找输入当前值,在树中对应的位置 
    {
    	while(r>=l)
    	{
    		int mid=(l+r)>>1;
    		if(rec[mid]==pos)
    		    return mid;
    		else if(rec[mid]>pos)
    		    r=mid-1;
    		else
    		    l=mid+1;
    	}
    	return -1;
    }
    int main()
    {
    	int t,n,m,k,i;
    	scanf("%d",&t);
    	k=1;
    	int maxx;
    	while(t--)
    	{
    		scanf("%d%d",&n,&m);
    		int p=1;
    	    for(i=0;i<n;i++)
    	    {
    	    	scanf("%d%d",&s[i],&e[i]);
    	    	rec[p++]=s[i];
    	    	rec[p++]=e[i];
    	    }
    	    for(i=0;i<m;i++)
    	    {
    	    	scanf("%d",&q[i]);
    	    	rec[p++]=q[i];
    	    }
    	    sort(rec+1,rec+p);//
    	    int R=2;
    	    for(i=2;i<p;i++)//去除数组中重复的点 
    	    {
    	    	if(rec[i]!=rec[i-1])
    	    	    rec[R++]=rec[i];
    	    }
    	    sort(rec+1,rec+R);
    		gettree(1,1,R-1);//对下标建树 
    		for(int i=0;i<n;i++)
    		{
    			int x=query(1,R-1,s[i]);
    			int y=query(1,R-1,e[i]);
    			update(1,1,R-1,x,y,1);
    		} 
    		printf("Case #%d:
    ",k++);
    		for(i=0;i<m;i++)
    		{
    			int x=query(1,R-1,q[i]);
    			printf("%d
    ",find(1,1,R-1,x)); 
    		}
    	}
    }
    

      

  • 相关阅读:
    Execl获取真实行数
    日期工具类
    Eclipse & IDEA快捷键对比大全
    【转】IDEA导入Eclipse项目 详细步骤(亲自验证导入成功)
    京东的四大集团
    马云演讲视频
    阿里系的一些重要网站
    阿里系的几个电商网站
    腾讯几款QQ软件
    电脑版微信使用说明
  • 原文地址:https://www.cnblogs.com/tonghao/p/4972639.html
Copyright © 2011-2022 走看看