[BZOJ2850]巧克力王国(KDtree)

有了KDtree+线段树区间查询的基础这题就很好做了。

首先用KDtree维护矩阵内的权值总和以及分裂点权值,之后在查询的时候把矩阵的四个点都check一遍,

如果都满足就直接加上总权值,如果都不满足就return,否则check分裂点更新答案之后递归左右分裂区间。

这道题做了1个多小时,当时主要卡到了矩阵四个点的check上,而我想的是只枚举两个端点但需要大量的分类讨论,而且y==0的情况需要用前缀和特殊处理

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<string>
#include<cstring>
#include<map>
#define int long long
#define max(a,b) (a>b?a:b)
#define min(a,b) (a>b?b:a)
#define m(a) memset(a,0,sizeof(a))
#define AA cout<<"Alita"<<endl
using namespace std;
const int N=5e4+10;
int size,ans,n,m,now;
struct point
{
        int x[2],w;
        int dis(point &b)
        {
                return abs(x[0]-b.x[0])+abs(x[1]-b.x[1]);
        }
        
}s[N];
bool comp(point a,point b)
{
        return a.x[now]<b.x[now];
}
struct KDtree
{
        KDtree *ch[2];
        int mn[2],mx[2],sum;
        point p;
        void init(point g)
        {
                ch[0]=ch[1]=NULL;
                sum=g.w;
                p=g;
                mn[0]=mx[0]=g.x[0];
                mn[1]=mx[1]=g.x[1];
        }
        void update(KDtree *k)
        {
                sum+=k->sum;
                mn[0]=min(mn[0],k->mn[0]);
                mx[0]=max(mx[0],k->mx[0]);
                mn[1]=min(mn[1],k->mn[1]);
                mx[1]=max(mx[1],k->mx[1]);
        }
        void pushup()
        {
                if(ch[0]!=NULL) update(ch[0]);
                if(ch[1]!=NULL) update(ch[1]);
        }
        
}*root,a[N];
void build(KDtree *& k,int l,int r,int typ)
{
        if(l>r) return;
        k=a+(size++);
        int mid=(l+r)>>1;
        now=typ;
        nth_element(s+l,s+mid,s+r+1,comp);
        k->init(s[mid]);
        build(k->ch[0],l,mid-1,typ^1);
        build(k->ch[1],mid+1,r,typ^1);
        k->pushup();
}
bool check(int x,int y,int A,int B,int C)
{
        if(x*A+y*B<C) return true;
        return false;
}
void query(KDtree *k,int x,int y,int z)
{
        if(k==NULL) return;
        if(!check(k->mn[0],k->mn[1],x,y,z)&&
           !check(k->mn[0],k->mx[1],x,y,z)&&
           !check(k->mx[0],k->mn[1],x,y,z)&&
           !check(k->mx[0],k->mx[1],x,y,z)) return;
        if(check(k->mn[0],k->mn[1],x,y,z)&&
           check(k->mn[0],k->mx[1],x,y,z)&&
           check(k->mx[0],k->mn[1],x,y,z)&&
           check(k->mx[0],k->mx[1],x,y,z))
        {
                ans+=k->sum;
                return;
        }
        if(k->p.x[0]*x+k->p.x[1]*y<z) ans+=k->p.w;
        if(k->ch[0]!=NULL) query(k->ch[0],x,y,z);
        if(k->ch[1]!=NULL) query(k->ch[1],x,y,z);
}
signed main()
{
        //freopen("1.in","r",stdin);
        //freopen("1.out","w",stdout);
        scanf("%lld%lld",&n,&m);
        for(int i=1;i<=n;i++)
        {
                scanf("%lld%lld%lld",&s[i].x[0],&s[i].x[1],&s[i].w);
        }
        build(root,1,n,0);
        for(int i=1,x,y,z;i<=m;i++)
        {
                ans=0;
                scanf("%lld%lld%lld",&x,&y,&z);
                query(root,x,y,z);
                printf("%lld\n",ans);
        }
        return 0;
}
View Code

 

posted @ 2019-08-04 12:15  ATHOSD  阅读(104)  评论(0编辑  收藏  举报