NYOJ 600 花儿朵朵 树状数组


花儿朵朵

时间限制: 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
和“士兵杀敌二”相像, 但是数据范围太大了,不能直接开数组,用离散化,或者哈希 数据有点水,我直接取余就水过了
#include <algorithm>
#include <iostream>
#include <cstring>//树状数组模板————插入区间求单点
#include <cstdlib>
#include <string>
#include <vector>
#include <cstdio>
#include <cmath>
#include <map>
#define FLAG 0
#define M 999983//一个很大的素数,因为我数组取的是100万,所以取了100万以下的最大素数
using namespace std;//这里可能存在问题,就是没有去重,如果取余之后有重复,这样就不行了
                    //我想是这一题的数据出的太水了,所以蒙混过关了

int c[1000005];//全局变量数组c 用lowbit函数建立成树状数组

int lowbit(int x)//重要建树、查找、连接函数
{
    return x&(-x);
}

void add(int x,int d)//区间修改,如果给定阿健a——b上各加d ,
{                   //需要调用两次:add(a-1,-d);add(b,d);
    while(x>0)
    {
        c[x]+=d;x-=lowbit(x);
    }
}
int get(int x)  //获取单点的值(查询)
{
    int sum=0;
    while(x<1000000)//1000000是数组的最大长度,就是取余后数据的最大范围
    {
        sum+=c[x];x=x+lowbit(x);
    }
    return sum;
}
int main()
{
	#if(FLAG)
        freopen("in.txt", "r", stdin);
		//freopen("out.txt", "w", stdout);
	#endif
	int n;
	int T,m,i,j,x,y;
	scanf("%d",&T);
	while(T--)
	{
	    memset(c,0,sizeof(c));
	    scanf("%d%d",&n,&m);
	    for(i=0;i<n;i++)
	    {
	        scanf("%d%d",&x,&y);
	        x=x%M;
	        y=y%M;//每次都对x,y进行处理之后进行运算
	        add(x-1,-1);
	        add(y,1);
	    }
	    for(i=0;i<m;i++)
	    {
	        scanf("%d",&x);
	        x=x%M;//询问的时候做同样的运算
	        printf("%d\n",get(x));
	    }
	}




	return 0;
}


如果数据卡一点估肯定不过,还是离散化+去重的保险


 
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define lowbit(a) a&-a
#define MaxN 300005
int m[MaxN], real[MaxN], N;
typedef struct
{
    int val, pos;
}S;

S mm[MaxN];

bool cmp(S a, S b)
{
    if(a.val==b.val) return a.pos>b.pos;
    return a.val<b.val;
}

void Add(int i, int num)
{
    while(i<=N)
    {
        m[i]+=num;
        i+=lowbit(i);
    }
}

int Sum(int i)
{
    int res=0;
    while(i>0)
    {
        res+=m[i];
        i-=lowbit(i);
    }
    return res;
}

int main()
{
	int T, temp, k, n;
	scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&k);
        N=2*n+k;
        memset(m,0,sizeof(m));
        for(int i=1;i<=N;i++)
        {
            scanf("%d",&temp);
            mm[i].pos=i;
            mm[i].val=temp;
        }
        sort(mm+1,mm+N+1,cmp);
        int x=0;
        for(int i=1;i<=N;i++)              //离散化+去重
        {
            if( mm[i].val != mm[i-1].val)
                real[mm[i].pos]=++x;
            else
                real[mm[i].pos]=x;
        }
        for(int i=1;i<=2*n;i+=2)            //插线
        {
            Add(real[i],1);
            Add(real[i+1]+1,-1);
        }
        for(int i=2*n+1;i<=N;i++)           //问点
            printf("%d\n",Sum(real[i]));
    }
	return 0;
}        



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值