正题
题目大意
有若干个红点和蓝点,对于每一对红点和蓝点,若距离大于DDD则蓝点压制红点,否则红点压制蓝点。然后红点和蓝点之间也有不定的压制关系。
求有多少个三角要求AAA压制BBB,BBB压制CCC,CCC压制AAA且至少包含一个红点和蓝点。求三角数量的最小值和最大值。
解题思路
我们考虑最暴力的做法先,我们可以枚举两个相同颜色的点,枚举他们之间的关系,然后找三角。
我们定义covxcov_xcovx表示在xxx的DDD范围以内与他异色的点的数量,covx,ycov_{x,y}covx,y表示同时在x,yx,yx,y两个点的DDD范围内的异色点的数量,对于包含两个红色点的方案数为
∑x,y∈redmax{covx−covx,y,covy−covx,y}\sum_{x,y\in red}max\{cov_x-cov_{x,y},cov_{y}-cov_{x,y}\}x,y∈red∑max{covx−covx,y,covy−covx,y}
∑x,y∈redmax{covx,covy}−covx,y\sum_{x,y\in red}max\{cov_x,cov_y\}-cov_{x,y}x,y∈red∑max{covx,covy}−covx,y
∑x,y∈redmax{covx,covy}−∑z∈bluecovx,y\sum_{x,y\in red}max\{cov_x,cov_y\}-\sum_{z\in blue} cov_{x,y}x,y∈red∑max{covx,covy}−z∈blue∑covx,y
那我们发现对于每个蓝点zzz被统计的次数就是Ccovz2C_{cov_z}^{2}Ccovz2
⇒∑x,y∈redmax{covx,covy}−∑z∈blueCcovz2\Rightarrow \sum_{x,y\in red}max\{cov_x,cov_y\}-\sum_{z\in blue} C_{cov_z}^{2}⇒x,y∈red∑max{covx,covy}−z∈blue∑Ccovz2
然后我们发现如果计算出covcovcov数组即可在O(nlogn)O(n\log n)O(nlogn)的时间内统计答案(排个序瞎搞搞就好)
那如何统计covcovcov数组,我们可以将每个点(x,y)(x,y)(x,y)转换为(x−y,x+y)(x-y,x+y)(x−y,x+y)然后将曼哈顿距离转换为切比雪夫距离。这样我们发现covcovcov就是在(x,y)(x,y)(x,y)这个点为中心的2D∗2D2D*2D2D∗2D的矩阵包含的点的个数,用扫描线统计即可。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=200100;
struct node{ll x,y;
}a[N],b[N];
ll n,m,D,y[N*3],mov,maxs,mins,covn[N],covm[N],cnt;
struct Seq_node{struct Tree_node{ll l,r,w;}t[N*16];void Build(ll x,ll l,ll r){t[x].l=l;t[x].r=r;if(l==r) return;ll mid=(l+r)/2;Build(x*2,l,mid);Build(x*2+1,mid+1,r);}ll Ask(ll x,ll l,ll r){if(t[x].l==l&&t[x].r==r)return t[x].w;ll mid=(t[x].l+t[x].r)/2;if(r<=mid) return Ask(x*2,l,r);else if(l>mid) return Ask(x*2+1,l,r);else return Ask(x*2,l,mid)+Ask(x*2+1,mid+1,r);}void Change(ll x,ll pos,ll val){if(t[x].l==t[x].r){t[x].w+=val;return;}ll mid=(t[x].l+t[x].r)/2;if(pos<=mid) Change(x*2,pos,val);else Change(x*2+1,pos,val);t[x].w=t[x*2].w+t[x*2+1].w;}
}T;
bool cMp(node x,node y)
{return x.x<y.x;}
int main()
{freopen("mhw.in","r",stdin);freopen("mhw.out","w",stdout);scanf("%lld%lld%lld",&n,&m,&D);for(ll i=1;i<=n;i++){ll X,Y;scanf("%lld%lld",&X,&Y);a[i].x=X+Y;a[i].y=X-Y;y[++cnt]=a[i].y;y[++cnt]=a[i].y+D;y[++cnt]=a[i].y-D;}for(ll i=1;i<=m;i++){ll X,Y;scanf("%lld%lld",&X,&Y);b[i].x=X+Y;b[i].y=X-Y;y[++cnt]=b[i].y;y[++cnt]=b[i].y+D;y[++cnt]=b[i].y-D;} sort(b+1,b+1+m,cMp);sort(a+1,a+1+n,cMp);sort(y+1,y+1+cnt);cnt=unique(y+1,y+1+cnt)-(y+1);T.Build(1,1,cnt);ll l=0,r=0;for(ll i=1;i<=n;i++){while(l<m&&b[l+1].x<a[i].x-D){ll Y=lower_bound(y+1,y+1+cnt,b[++l].y)-y;T.Change(1,Y,-1);}while(r<m&&b[r+1].x<=a[i].x+D){ll Y=lower_bound(y+1,y+1+cnt,b[++r].y)-y;T.Change(1,Y,1);}ll L=lower_bound(y+1,y+1+cnt,a[i].y-D)-y,R=lower_bound(y+1,y+1+cnt,a[i].y+D)-y;covn[i]=T.Ask(1,L,R);}while(l<m){ll Y=lower_bound(y+1,y+1+cnt,b[++l].y)-y;T.Change(1,Y,-1);}while(r<m){ll Y=lower_bound(y+1,y+1+cnt,b[++r].y)-y;T.Change(1,Y,1);}l=0,r=0;for(ll i=1;i<=m;i++){while(l<n&&a[l+1].x<b[i].x-D){ll Y=lower_bound(y+1,y+1+cnt,a[++l].y)-y;T.Change(1,Y,-1);}while(r<n&&a[r+1].x<=b[i].x+D){ll Y=lower_bound(y+1,y+1+cnt,a[++r].y)-y;T.Change(1,Y,1);}ll L=lower_bound(y+1,y+1+cnt,b[i].y-D)-y,R=lower_bound(y+1,y+1+cnt,b[i].y+D)-y;covm[i]=T.Ask(1,L,R);}sort(covn+1,covn+1+n);sort(covm+1,covm+1+m);for(ll i=1;i<=n;i++)maxs+=covn[i]*(i-1),mins+=covn[i]*(n-i),mov+=covn[i]*(covn[i]-1)/2;for(ll i=1;i<=m;i++)maxs+=covm[i]*(i-1),mins+=covm[i]*(m-i),mov+=covm[i]*(covm[i]-1)/2;printf("%lld %lld",mins-mov,maxs-mov);
}