题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2850
改一下估价即可。判断子树能否整个取或者是否整个不能取,时间好像就能行了?
因为有负数,所以判一下四个边界。注意这个区域本身还占了一个点。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const int N=5e4+5; int n,m,rt,tot,fx; ll A,B,C; struct Dt{ ll x[2],y[2],p[2],h,ph; }a[N]; bool cmp(Dt u,Dt v){return u.p[fx]<v.p[fx];} struct KD{ int c[N][2];Dt s[N]; void add(int cr,Dt k) { for(int i=0;i<=1;i++) s[cr].x[i]=s[cr].y[i]=s[cr].p[i]=k.p[i]; s[cr].h=s[cr].ph=k.h; } void pshp(int cr) { int ls=c[cr][0],rs=c[cr][1]; for(int i=0;i<=1;i++) { if(ls) s[cr].x[i]=min(s[cr].x[i],s[ls].x[i]), s[cr].y[i]=max(s[cr].y[i],s[ls].y[i]); if(rs) s[cr].x[i]=min(s[cr].x[i],s[rs].x[i]), s[cr].y[i]=max(s[cr].y[i],s[rs].y[i]); } s[cr].h=(ls?s[ls].h:0)+(rs?s[rs].h:0)+s[cr].ph; } void build(int &cr,int l,int r,bool now) { int mid=l+r>>1; fx=now; nth_element(a+l,a+mid,a+r+1,cmp); cr=++tot; add(cr,a[mid]); if(l<mid) build(c[cr][0],l,mid-1,!now); if(mid<r) build(c[cr][1],mid+1,r,!now); pshp(cr); // printf("cr=%d(x:%lld~%lld y:%lld~%lld h=%lld) ",cr,s[cr].x[0], // s[cr].y[0],s[cr].x[1],s[cr].y[1],s[cr].h); } int check(int cr) { int ret=0; ret+=(A*s[cr].x[0]+B*s[cr].x[1]<C); ret+=(A*s[cr].x[0]+B*s[cr].y[1]<C); ret+=(A*s[cr].y[0]+B*s[cr].x[1]<C); ret+=(A*s[cr].y[0]+B*s[cr].y[1]<C); return ret; } ll query(int cr) { ll ret=(A*s[cr].p[0]+B*s[cr].p[1]<C?s[cr].ph:0); int ls=c[cr][0],rs=c[cr][1]; int dl=(ls?check(ls):0),dr=(rs?check(rs):0); // printf("cr=%d(x:%lld~%lld y:%lld~%lld h=%lld) dl=%d dr=%d " // ,cr,s[cr].x[0],s[cr].y[0],s[cr].x[1],s[cr].y[1],s[cr].h,dl,dr); if(dl==4) ret+=s[ls].h; else if(dl) ret+=query(ls); if(dr==4) ret+=s[rs].h; else if(dr) ret+=query(rs); return ret; } }kd; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%lld%lld%lld",&a[i].p[0],&a[i].p[1],&a[i].h); kd.build(rt,1,n,0); for(int i=1;i<=m;i++) { scanf("%lld%lld%lld",&A,&B,&C); printf("%lld ",kd.query(rt)); } return 0; }