BZOJ2850: 巧克力王国 kdtree

题意:n个平面上的带权点,每次给出a,b,h,询问满足ax+by < h的点权和。
1 <= n, m <= 50000,其它10^9
kdtree划分矩形,显然若矩形四个顶点都在半平面内,则整个矩形在半平面内;四个顶点都在半平面外,则整个矩形在半平面外。
注意维护的是权值和,不是size

#include<cstdio>
#include<algorithm>
using std::nth_element;
typedef long long ll;
struct chok
{
    int p[2],v;
    chok(){}
    chok(int x,int y,int z):v(z){p[0]=x,p[1]=y;}
    inline int& operator [] (size_t x){return p[x];}
    inline const int& operator [] (size_t x) const {return p[x];}
};
inline int check(ll a,ll b,ll c,int x,int y)
{
    return a*x+b*y<c;
}
bool cmp;
inline bool fn(const chok &a,const chok &b)
{
    return a[cmp]<b[cmp];
}
inline void min(int &a,int b)
{
    if(b<a) a=b;
}
inline void max(int &a,int b)
{
    if(a<b) a=b;
}
struct node
{
    ll sum;
    chok p;
    int xn,yn,xm,ym;
    node *l,*r;
    node(const chok &p):sum(p.v),p(p),l(0),r(0),xn(p[0]),yn(p[1]),xm(p[0]),ym(p[1]){}
    inline void* operator new(size_t)
    {
        static unsigned char pool[50000*sizeof(node)];
        static node* s=(node*)pool;
        static size_t k=-1;
        return s+ ++k;
    }
    ll query(int a,int b,int c)
    {
        if(!this) return 0;
        int tot=check(a,b,c,xn,yn)+check(a,b,c,xn,ym)+check(a,b,c,xm,yn)+check(a,b,c,xm,ym);
        if(tot==4) return sum;
        if(!tot) return 0;
        ll res=0;
        if(check(a,b,c,p[0],p[1])) res+=p.v;
        return res+l->query(a,b,c)+r->query(a,b,c);
    }
    inline void up()
    {
        if(l) min(xn,l->xn),min(yn,l->yn),max(xm,l->xm),max(ym,l->ym),sum+=l->sum;
        if(r) min(xn,r->xn),min(yn,r->yn),max(xm,r->xm),max(ym,r->ym),sum+=r->sum;
    }
};
struct kdtree
{
    node *rt;
    node *build(chok* l,chok *r,bool k)
    {
        if(l==r) return 0;
        chok *mid=l+(r-l>>1);
        cmp=k;
        nth_element(l,mid,r,fn);
        node *kre=new node(*mid);
        kre->l=build(l,mid,!k);
        kre->r=build(mid+1,r,!k);
        kre->up();
        return kre;
    }
    kdtree(chok *a,int len):rt(build(a,a+len,0)){}
    inline ll query(int a,int b,int c)
    {
        return rt->query(a,b,c);
    }
};
int n,m;
chok choco[50000];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;++i)
    scanf("%d%d%d",&choco[i].p[0],&choco[i].p[1],&choco[i].v);
    kdtree tr(choco,n);
    for(int i=0;i<m;++i)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        printf("%lld\n",tr.query(a,b,c));
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值