花儿朵朵

来源:互联网 发布:手机归属地数据库 编辑:程序博客网 时间:2024/04/30 07:51

花儿朵朵

时间限制: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行,每行有一个整数,代表游客询问的时间。
输出
对于每次游客的询问,输出一个整数在单独的一行,表示这个时间盛开的花有多少种。
样例输入
21 15 1042 31 44 8146
样例输出
0121

思路:

树状数组的应用(插线求点),但是数据太过“离散”, 需要将各节点重新编号, 主要的难点就是离散化操作, 需要先记录输入顺序, 然后将节点排序, 再将节点重新编号, exchange[i]表示输入顺序为i的节点在树状数组内的新位置, 然后就是树状数组的插线求点操作。

#include <stdio.h>#include <string.h>#include <stdlib.h>#include <algorithm>using namespace std;#define MAX_NUM 200002typedef struct Node{int num, id;}node;node input[MAX_NUM];int tree[MAX_NUM], exchange[MAX_NUM];bool cmp(node a, node b){return a.num < b.num;}int lowbit(int x){return x&(-x);}int getsum(int n, int side)                  //求节点的值{int temp = 0;while(n <= side){temp += tree[n];n += lowbit(n);}return temp;}int add(int n, int val)                       //插线{while(n > 0){tree[n] += val;n -= lowbit(n);}return 0;}int main(){int cnt, n, m, i, t, sum;scanf("%d", &t);while(t--){memset(tree, 0, sizeof(tree));               //初始化数组memset(exchange, 0, sizeof(exchange));scanf("%d%d", &n,&m);sum = n * 2 + m;                              //sum: 总节点数for(i = 0; i < sum; i++){scanf("%d", &input[i].num);input[i].id = i;                           //记录输入顺序,在树状数组中插线时要用}sort(input, input+sum, cmp);                    //将节点排序cnt = 0;exchange[input[0].id] = ++cnt;                   //重新编号节点for(i = 1; i < sum; i++){if(input[i].num != input[i-1].num){exchange[input[i].id] = ++cnt;}else{exchange[input[i].id] = cnt;}}for(i = 0; i < n*2; i += 2)                      //上面说的按id排序, 每两组是一条线段{add(exchange[i+1], 1);add(exchange[i]-1, -1);}for(i = n*2; i < sum; i++){printf("%d\n", getsum(exchange[i], cnt));    //打印节点}}return 0;}


0 0