巧克力王国

link

可以认为是K-D树模板题。当然这只是不带修改的K-D树,带修的以后写了再说。

作为一篇学习笔记,先介绍一下什么是K-D树。要明白一点,即K是一个变量,用来指代此数据结构处理和维护的空间维数,比如要维护平面上的点或者二元组集合那么就应该叫做2-D树(不然真的以为是kbd卡丹树吗,那样叫实在有点不雅)。接下来说一下它的思想。它的本质就是对于一个Nk维空间进行分治维护,相当于改良优化后的k维树状数组(当然它们有很多地方是不一样的)。哪e2-D树来说,它考虑的是把平面分割成一个个矩形,每个节点对应一个矩形,随着树的递归建造矩形被越分越小最后成为一个单点。由于每个节点是一个矩形,那么就可以考虑把这个矩形当成一个整体进行询问和修改,具体方式看题。最后,如果带插入的话可能会导致树的结构失衡,此时就需要使用替罪羊一样的方式进行拍扁重建,当然那都是后话了。

考虑到这道题,本质上它就是要询问满足\(ax+by<c\)的点\((x,y)\)的个数。很显然前面的表达式相当于一个半平面,而一个矩形只有三种情况,全不在半平面中全在以及一部分在。前两种情况可以直接看成一个整体累加答案,后面那种情况递归处理就可以了。复杂度……应该是\(O(NlogN)\)吧,毕竟它有分治在里面的嘛。

code:

#include<cstdio>
#include<algorithm>
//#define zczc
#define ll long long
using namespace std;
const int N=50010;
const int maxn=1e9;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
    wh*=f;return;
}
inline int min(int s1,int s2){return s1<s2?s1:s2;}
inline int max(int s1,int s2){return s1<s2?s2:s1;}

int m,n;
#define lc t[wh].l
#define rc t[wh].r
struct node{
	int x,y,l,r,num,sx,sy,bx,by;ll sum;
}t[N],a[N];
int cnt;bool kkk;
inline bool cmp(node s1,node s2){
	if(kkk)return s1.x==s2.x?s1.y<s2.y:s1.x<s2.x;
	else return s1.y==s2.y?s1.x<s2.x:s1.y<s2.y;
}
inline void pushup(int wh){
	t[wh].sx=min(min(t[lc].sx,t[rc].sx),t[wh].x);
	t[wh].sy=min(min(t[lc].sy,t[rc].sy),t[wh].y);
	t[wh].bx=max(max(t[lc].bx,t[rc].bx),t[wh].x);
	t[wh].by=max(max(t[lc].by,t[rc].by),t[wh].y);
	t[wh].sum=t[lc].sum+t[rc].sum+t[wh].num;
}
int build(int l,int r,bool k){
	if(l>r)return 0;int wh=++cnt,mid=l+r>>1;kkk=k;
	nth_element(a+l,a+mid,a+r+1,cmp);t[wh]=a[mid];
	lc=build(l,mid-1,!k),rc=build(mid+1,r,!k);
	return pushup(wh),wh;
}
ll ans;int aa,b,c;
inline bool in(int x,int y){return 1ll*aa*x+1ll*b*y<c;}
inline int inn(int wh){
	int num=0;//-1全不在半平面,1全在,0不完全在 
	num+=in(t[wh].sx,t[wh].sy);num+=in(t[wh].sx,t[wh].by);
	num+=in(t[wh].bx,t[wh].sy);num+=in(t[wh].bx,t[wh].by);
	if(num==0)return -1;if(num==4)return 1;return 0;
}
void solve(int wh){
	if(!wh)return;if(in(t[wh].x,t[wh].y))ans+=t[wh].num;
	int ls=inn(lc),rs=inn(rc);
	if(ls==1)ans+=t[lc].sum;if(rs==1)ans+=t[rc].sum;
	if(ls==0)solve(lc);if(rs==0)solve(rc);
}
#undef lc
#undef rc

signed main(){
	
	#ifdef zczc
	freopen("in.txt","r",stdin);
	#endif
	
	t[0].sx=t[0].sy=maxn,t[0].bx=t[0].by=-maxn;
	read(m);read(n);
	for(int i=1;i<=m;i++){read(a[i].x);read(a[i].y);read(a[i].num);}
	int root=build(1,m,true);
	for(int i=1;i<=n;i++){
		read(aa);read(b);read(c);ans=0;solve(root);printf("%lld\n",ans);
	}
	
	return 0;
}
上一篇:AtCoder Beginner Contest 240


下一篇:ASP.NET连接数据库时,提示“用户 'sa' 登录失败原因: 未与信任 SQL Server 连接相关联