题目大意,求在给定要求内的数据之和。
挺简洁的,一样对于数据建树,维护一个\(sum\)美味度的和,上下界变成甜度,\(query\)时判断是不是满足客户甜度要求,如果四种搭配\((mi[0]->mx[1],mi[0]->mi[1],mx[0]->mi[1],mx[0]->mx[1])\)
均符合要求,则说明这整个区间答案都属于贡献,直接加\(sum\)即可。
否则,判断一波当前走到的点能不能贡献,然后分左右查询即可。
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; #define int long long const int MAXN=5e5+10; //挺简单的基础K-D_TREE struct pt{ int x[2],cnt; }p[MAXN]; struct node{ int siz,mi[2],mx[2],sum; //sum维护区间和 pt c; }tr[MAXN]; int n,m,rt,tot,D; int ls[MAXN],rs[MAXN]; int operator<(pt a,pt b){return a.x[D]<b.x[D];} inline void pushup(int x){ int l=ls[x],r=rs[x]; tr[x].siz=tr[l].siz+tr[r].siz+1; tr[x].sum=tr[l].sum+tr[r].sum+tr[x].c.cnt; for(int i=0;i<=1;++i){ tr[x].mi[i]=tr[x].mx[i]=tr[x].c.x[i]; if(l)tr[x].mi[i]=min(tr[x].mi[i],tr[l].mi[i]),tr[x].mx[i]=max(tr[x].mx[i],tr[l].mx[i]); if(r)tr[x].mi[i]=min(tr[x].mi[i],tr[r].mi[i]),tr[x].mx[i]=max(tr[x].mx[i],tr[r].mx[i]); } //更新子树信息 } int build(int l,int r,int d){ if(l>r)return 0; int x=++tot,mid=l+r>>1; D=d;nth_element(p+l,p+mid,p+r+1); tr[x].c=p[mid];ls[x]=build(l,mid-1,d^1); rs[x]=build(mid+1,r,d^1);pushup(x);return x; } int A,B,C; inline bool check(int x,int y){return A*x+B*y<C;} int query(int x){ //区间查询 int t=0,res=0; t+=check(tr[x].mi[0],tr[x].mi[1]); t+=check(tr[x].mi[0],tr[x].mx[1]); t+=check(tr[x].mx[0],tr[x].mi[1]); t+=check(tr[x].mx[0],tr[x].mx[1]); if(t==4)return tr[x].sum;//如果这个区间完全在查询范围 else if(t==0)return 0;//完全不在 if(check(tr[x].c.x[0],tr[x].c.x[1]))res+=tr[x].c.cnt;//判断这个点在不在 if(ls[x])res+=query(ls[x]);//分成两边累加答案 if(rs[x])res+=query(rs[x]); return res; } signed main(){ scanf("%lld%lld",&n,&m); for(int i=1;i<=n;++i) scanf("%lld%lld%lld",&p[i].x[0],&p[i].x[1],&p[i].cnt); rt=build(1,n,0); for(int i=1;i<=m;++i){ scanf("%lld%lld%lld",&A,&B,&C); printf("%lld\n",query(rt)); } return 0; }