【BZOJ2850】巧克力王国

Description

巧克力王国里的巧克力都是由牛奶和可可做成的。但是并不是每一块巧克力都受王国人民的欢迎,因为大家都不喜
欢过于甜的巧克力。对于每一块巧克力,我们设x和y为其牛奶和可可的含量。由于每个人对于甜的程度都有自己的
评判标准,所以每个人都有两个参数a和b,分别为他自己为牛奶和可可定义的权重,因此牛奶和可可含量分别为x
和y的巧克力对于他的甜味程度即为ax + by。而每个人又有一个甜味限度c,所有甜味程度大于等于c的巧克力他都
无法接受。每块巧克力都有一个美味值h。现在我们想知道对于每个人,他所能接受的巧克力的美味值之和为多少
Input

第一行两个正整数n和m,分别表示巧克力个数和询问个数。接下来n行,每行三个整数x,y,h,含义如题目所示。再
接下来m行,每行三个整数a,b,c,含义如题目所示。
Output

输出m行,其中第i行表示第i个人所能接受的巧克力的美味值之和。
Sample Input

3 3

1 2 5

3 1 4

2 2 1

2 1 6

1 3 5

1 3 7
Sample Output

5

0

4
HINT

1 <= n, m <= 50000,1 <= 10^9,-10^9 <= a, b, x, y <= 10^9。

Source

Violet 0

如果整个矩阵的点都不会超过限制,那可以直接获取矩阵答案
否则就递归

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 50010
#define Dnum 2
#define LL long long
#define GET (ch>='0'&&ch<='9')
using namespace std;
inline void in(int &x)
{
    char ch=getchar();x=0;int flag=1;
    while (!GET)    flag=ch=='-'?-1:1,ch=getchar();
    while (GET) x=x*10+ch-'0',ch=getchar();x*=flag;
}
inline void llin(LL &x)
{
    char ch=getchar();x=0;int flag=1;
    while (!GET)    flag=ch=='-'?-1:1,ch=getchar();
    while (GET) x=x*10+ch-'0',ch=getchar();x*=flag;
}
LL ans;
int n,m,root;
long long a,b,lim;
bool cmp_d;
struct KDtree
{
    int ch[2],d[Dnum],minn[Dnum],maxn[Dnum],val; LL sum;
    inline bool operator < (const KDtree& a)const   {   return d[cmp_d]<a.d[cmp_d]; }
    inline void init()  {   sum=val;    for (int i=0;i<Dnum;++i)    minn[i]=maxn[i]=d[i];   }
}tree[MAXN];
inline bool check(int x,int y)  {   return a*x+b*y<lim; }
inline int calc(int rt)
{
    int ret=0;
    ret+=check(tree[rt].minn[0],tree[rt].minn[1]);ret+=check(tree[rt].minn[0],tree[rt].maxn[1]);
    ret+=check(tree[rt].maxn[0],tree[rt].minn[1]);ret+=check(tree[rt].maxn[0],tree[rt].maxn[1]);
    return ret;
}
inline void push_up(int rt)
{
    tree[rt].sum=tree[rt].val;
    for (int i=0;i<2;++i)
        if (tree[rt].ch[i])
        {
            int x=tree[rt].ch[i];
            tree[rt].sum+=tree[x].sum;
            for (int j=0;j<2;++j)
                tree[rt].minn[j]=min(tree[rt].minn[j],tree[x].minn[j]),
                tree[rt].maxn[j]=max(tree[rt].maxn[j],tree[x].maxn[j]);
        }
}
int rebuild(int l=1,int r=n,bool d=0)
{
    cmp_d=d;int mid=(l+r)>>1;nth_element(tree+l,tree+mid,tree+r+1);
    tree[mid].init();
    if (l!=mid) tree[mid].ch[0]=rebuild(l,mid-1,d^1);
    if (r!=mid) tree[mid].ch[1]=rebuild(mid+1,r,d^1);
    return push_up(mid),mid;
}
void query(int rt=root)
{
    int l=tree[rt].ch[0],r=tree[rt].ch[1],cntl=l?calc(l):0,cntr=r?calc(r):0;
    if (check(tree[rt].d[0],tree[rt].d[1])) ans+=tree[rt].val;
    if (cntl==4)    ans+=tree[l].sum;
    else    if (cntl)   query(l);
    if (cntr==4)    ans+=tree[r].sum;
    else    if (cntr)   query(r);
}
int main()
{
    in(n);in(m);
    for (int i=1;i<=n;i++)  in(tree[i].d[0]),in(tree[i].d[1]),in(tree[i].val);
    for (root=rebuild();m;m--)
    {
        llin(a);llin(b);llin(lim);ans=0;
        query();printf("%lld\n",ans);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值