bzoj 2850 巧克力王国 —— K-D树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2850
只要暴力判断是否全选一个子树或全不选,如果都不是就进入查询;
要注意值有负,所以不是直接看 min 和 max 的组合,而是各种都试一遍;
pushup 时不要把 sum 累加写在循环里...
代码如下:
#include<cstdio> #include<cstring> #include<algorithm> #define mid ((l+r)>>1) using namespace std; typedef long long ll; int const xn=50005; int n,rt,cnt,dm,c[xn][2]; ll ans,A,B,C; struct N{ll mn[2],mx[2],p[2],ys,sum;}t[xn],a[xn]; ll rd() { ll ret=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return f?ret:-ret; } ll Min(ll x,ll y){return x<y?x:y;} ll Max(ll x,ll y){return x<y?y:x;} bool cmp(N x,N y){return x.p[dm]<y.p[dm];} void turn(int x,N v) { for(int i=0;i<2;i++)t[x].mn[i]=t[x].mx[i]=t[x].p[i]=v.p[i]; t[x].sum=t[x].ys=v.sum; } void pushup(int x) { int ls=c[x][0],rs=c[x][1]; t[x].sum=t[x].ys; for(int i=0;i<2;i++) { if(ls)t[x].mn[i]=Min(t[x].mn[i],t[ls].mn[i]),t[x].mx[i]=Max(t[x].mx[i],t[ls].mx[i]); if(rs)t[x].mn[i]=Min(t[x].mn[i],t[rs].mn[i]),t[x].mx[i]=Max(t[x].mx[i],t[rs].mx[i]); } if(ls)t[x].sum+=t[ls].sum; if(rs)t[x].sum+=t[rs].sum;// } void build(int &x,int l,int r,int nw) { x=++cnt; dm=nw; nth_element(a+l,a+mid,a+r+1,cmp); turn(x,a[mid]); if(mid>l)build(c[x][0],l,mid-1,nw^1); if(mid<r)build(c[x][1],mid+1,r,nw^1); pushup(x); } //bool in(int x){return (ll)t[x].mx[0]*A+(ll)t[x].mx[1]*B<C;} //bool out(int x){return (ll)t[x].mn[0]*A+(ll)t[x].mn[1]*B>=C;} int ck(int x) { int ret=0; ret+=((t[x].mn[0]*A+t[x].mn[1]*B)<C); ret+=((t[x].mn[0]*A+t[x].mx[1]*B)<C); ret+=((t[x].mx[0]*A+t[x].mn[1]*B)<C); ret+=((t[x].mx[0]*A+t[x].mx[1]*B)<C); return ret; } void query(int x) { if(t[x].p[0]*A+t[x].p[1]*B<C)ans+=t[x].ys;//! int ls=c[x][0],rs=c[x][1]; if(ls) { int d=ck(ls); if(d==4)ans+=t[ls].sum; else if(d)query(ls); } if(rs) { int d=ck(rs); if(d==4)ans+=t[rs].sum; else if(d)query(rs); } } int main() { n=rd(); int m=rd(); for(int i=1;i<=n;i++)a[i].p[0]=rd(),a[i].p[1]=rd(),a[i].sum=rd(); build(rt,1,n,0); for(int i=1;i<=m;i++) { A=rd(); B=rd(); C=rd(); ans=0; query(rt); printf("%lld\n",ans); } return 0; }