[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; }