HDU 3890 Apparent Magnitude 树状数组+离散化

/*
我们要找到在a,b左下方点的个数和权值和,只需要把x坐标不大于a的y值插入树状数组,然后统计y值小于b的个数个他们的权值和就行了。所以要得到正确答案,必须插入和查询同时进行(离线操作)——只有只插入x不大于a的y值的情况下统计出来才是正确答案。当然,由于y值范围大,值可能很稀疏,这样无疑会影响到插入和查询的时空效率。注意到,我们只关心比y小的个数和他们的权值,并不关心小多少之类的问题。所以把y按小到达映射成一个互异的升序数列可以很大得提高时空效率(离散化思想)
统计区间(a1,b1),(a2,b2)可以转换为统计
sum(b2,a2)-sum(a2,b1)-sum(a1,b2)+sum(a1,b1);								 
1 把所有的点以x升序排序p和qur数组
2 把所有y的坐标离散化
3 对于qur[i]把所有p[j].x小于qur[i].x的插入树状数组,并以qur[i].y统计
*/
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <set>
#include<map>
#include<ctime>
using namespace std;
const int MAXN = 180009;
const int N = 180009;
const int MAXV=60001;
const double eps = 1e-6;
struct point
{
    int x,y;
    double val;
    int id;
}p[MAXV],qur[2*MAXV];
bool cmp(point a,point b)
{
    return a.x<b.x;
}
int anscnt[MAXN];
double anssum[MAXN];
double var[MAXN];
//***********************************************************
//树状数组
int ar[MAXN],n,q;  
int lowb(int t){return t&(-t);}  
void add(int i,int v,double val)  
{  
    for(;i<N;ar[i]+=v,var[i]+=val,i+=lowb(i));  
}  
void sum(int i,int &s,double &val)  
{  
	s=0;val=0;  
    for(;i>0;s+=ar[i],val+=var[i],i-=lowb(i));  
}  
//***********************************************************
map<int,int> Map;//用做离散化y坐标
int main()
{
 
    while(scanf("%d%d",&n,&q)!=EOF)
    {
        memset(ar,0,sizeof(ar));
        memset(var,0,sizeof(var));
        memset(anscnt,0,sizeof(anscnt));
        memset(anssum,0,sizeof(anssum));
        Map.clear();
        for(int i=0;i<n;i++) 
        {
        scanf("%d%d%lf",&p[i].x,&p[i].y,&p[i].val);
        Map[p[i].y]=1;
        }
        for(int i=0;i<4*q;i=i+4)//一次区间查询对应4次普通查询
        {
        scanf("%d%d%d%d",&qur[i].x,&qur[i].y,&qur[i+3].x,&qur[i+3].y);
        qur[i].x--;
        qur[i].y--;
        qur[i].id=i;
        qur[i+1].id=i+1;
        qur[i+2].id=i+2;
        qur[i+3].id=i+3;
        qur[i+1].x=qur[i+3].x;
        qur[i+1].y=qur[i].y;
        qur[i+2].x=qur[i].x;
        qur[i+2].y=qur[i+3].y;
        Map[qur[i].y]=1;
        Map[qur[i+1].y]=1;
        Map[qur[i+2].y]=1;
        Map[qur[i+3].y]=1;
        }
        int k=0,g=0;
        for(map< int, int >::iterator it=Map.begin();it!=Map.end();it++)
        it->second=k++;//y的坐标值对应一个整数(从小到大)
        sort(p,p+n,cmp);
        sort(qur,qur+4*q,cmp);
        k=0,g=0;
        for(;;)
        {
            //cout<<p[k].y<<" "<<qur[g].y<<endl;
            if(k<n&&p[k].x<=qur[g].x)
            {
            add(Map[p[k].y],1,p[k].val);
            k++;
            }
            else 
            {
                sum(Map[qur[g].y],anscnt[qur[g].id],anssum[qur[g].id]);
                g++;//cout<<"t";
            }
            if(g>=4*q)break;
        }
        for(int i=0;i<4*q;i=i+4)
        printf("%.2lf/%d\n",anssum[i+3]-anssum[i+2]-anssum[i+1]+anssum[i]+eps,anscnt[i+3]-anscnt[i+2]-anscnt[i+1]+anscnt[i]);//避免-0.00,结果加上eps
    }
    return 0;
}




  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值