花儿朵朵
时间限制:
1000 ms | 内存限制:
65535 KB
难度:
5
-
描述
-
春天到了,花儿朵朵盛开,hrdv是一座大花园的主人,在他的花园里种着许多种鲜花,每当这个时候,就会有一大群游客来他的花园欣赏漂亮的花朵,游客们总是会询问,某个时间有多少种花儿同时在盛开着?hrdv虽然知道每种花儿的开花时间段,但是他不能很快的答出游客的问题,你能编写一个程序帮助他吗?
-
输入
- 第一行有个整数t,表示有t组测试数据,每组测试数据第一行为两个整数n,m(0<n<100000,0<m<100000);随后有n行,每一行有两个整数x,y(0<x<y<1000000000),表示这一种花的盛开时间是从x到y;随后有m行,每行有一个整数,代表游客询问的时间。 输出
- 对于每次游客的询问,输出一个整数在单独的一行,表示这个时间盛开的花有多少种。 样例输入
-
2 1 1 5 10 4 2 3 1 4 4 8 1 4 6
样例输出
-
0 1 2 1
这个一读题就感觉可以用线段树做,然后想了想用树状数组更好,就愉快的决定用取线问点了。但是问题就来了,题中给的数据是从1到10亿这么大的数据范围明显不能开出来。看了看别人的的讲解,说要离散化。鄙人就把自己对离散化的理解发出来,板砖轻拍。
先来看看百度里离散化的概念:离散化,把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率。其基本思想就是在众多可能的情况中“只考虑我需要用的值”。
光看到概念鄙人还是云里雾里的。后来写了几个数据推一推就想明白了:
6 4
100 1000
200 400
150 250
500 750
700 900
800 900
50
450
900
1200
对全部数据进行顺序存储然后在由小到大排序,建立如下的对应关系:
这样就相当于对数据进行了一个压缩,建立了一中映射。只考虑了我需要用的的数据,即 花儿开放的区间段(相同颜色的线),和顾客问的时间点(灰色的线)
像绿色的线:100-1000段的数据就映射成了2-13。段期间的值都是有需要的值。
把压缩前的数据用线段图表示:黑线段表示开花期间,红线表示这一时间点
把压缩后的数据用线段图表示:
这样只需要14个点就能存储,而压缩前要用1200个点。然后就是建立线段树或树状数组了,这些不懂的童鞋先做做士兵杀敌系列吧。
代码列出:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define Maxsize 300000
int a[Maxsize];
int b[Maxsize];
struct Node{
int id;
int data;
}d[Maxsize];
int num,n,m;
int com(const void *p,const void *q)
{
Node *r;
Node *t;
r=(Node *)p;t=(Node *)q;
return r->data-t->data;
}
int lowbit(int x)
{
return x&(-x);
}
int getsum(int x)//上溯寻值
{
int s=0;
while(x<=Maxsize)
{
s+=b[x];
x+=lowbit(x);
}
return s;
}
void update(int x,int y)
{
while(x>0)
{
b[x]+=y;
x-=lowbit(x);
}
}
int main()
{
int t;
int i;
int count;
scanf("%d",&t);
while(t--)
{
memset(b,0,sizeof(b));
d[0].data=-1;
d[0].id=-1;
scanf("%d%d",&n,&m);
num=n*2+m;
for(i=1;i<=num;i++)
{scanf("%d",&d[i].data);d[i].id=i;}
qsort(d,num+1,sizeof(Node),com);
count=0;
a[d[1].id]=++count;
for(i=1;i<=num;i++)
{
if(d[i].data!=d[i-1].data)
a[d[i].id]=++count;
else a[d[i].id]=count;
}
num=num-m;
for(i=2;i<=num;i+=2)
{
update(a[i],1);
update(a[i-1]-1,-1);
}
for(i=num+1;i<=num+m;i++)
{
printf("%d\n",getsum(a[i]));
}
}
return 0;
}