给出平面上的M条平行于坐标轴的线段,问有多少个正方形。
这题其实可以 O(n3) 暴力10秒卡过去……
对于一个点 (x,y) ,因为线段都是垂直于坐标轴的,我们可以计算出通过它的线段的四个端点。又因为每条线段没有重叠部分,所以可以用类似并查集的方法 O(n2) 处理出来。
那么暴力就是枚举每个点作为正方形的一个端点,然后枚举正方形的边长再判断。
把平面分成 2n 条对角线,可以证明每个正方形的两个对角肯定在同一条线段上。
然后对于每条对角线,题目可以转化为有多少对点在彼此的边长范围内。
主席树处理。
O(n2+n2logn)
轻松rank(倒数)1
#include
#include
#include
#include
#define N 1010
using namespace std;
int n,m,Ans,L[N][N],D[N][N],U[N][N],R[N][N];
inline void reaD(int &x){
char Ch=getchar();x=0;
for(;Ch>'9'||Ch<'0';Ch=getchar());
for(;Ch>='0'&&Ch<='9';x=x*10+Ch-'0',Ch=getchar());
}
int Sl(int x,int y){return L[x][y]<=y?y:L[x][y]=Sl(x,L[x][y]);}
int Sd(int x,int y){return D[x][y]<=x?x:D[x][y]=Sd(D[x][y],y);}
int Sr(int x,int y){return R[x][y]>=y?y:R[x][y]=Sr(x,R[x][y]);}
int Su(int x,int y){return U[x][y]>=x?x:U[x][y]=Su(U[x][y],y);}
struct ft{
struct tr{
int l,r,ls,rs,x;
}T[N<<4];
int t,rt[N],tc;
void InserT(int &x,int y,int d){
x=++t;
T[x]=T[y];
T[x].x++;
if(T[x].l==T[x].r) return ;
int mid=T[x].l+T[x].r>>1;
if(d<=mid) InserT(T[x].ls,T[y].ls,d);
else InserT(T[x].rs,T[y].rs,d);
}
int QuerY(int x,int l,int r){
if(T[x].l==l&&T[x].r==r) return T[x].x;
int mid=T[x].l+T[x].r>>1;
if(r<=mid) return QuerY(T[x].ls,l,r);
if(l>mid) return QuerY(T[x].rs,l,r);
return QuerY(T[x].ls,l,mid)+QuerY(T[x].rs,mid+1,r);
}
void build(int &x,int l,int r){
x=++t;
T[x].l=l;T[x].r=r;
if(l==r) return;
int mid=l+r>>1;
build(T[x].ls,l,mid);
build(T[x].rs,mid+1,r);
}
inline void build(){
build(rt[0],1,n+1);
tc=t;
}
inline void clear(){t=tc;}
inline void Insert(int x,int L,int d){
rt[x]=rt[x-1];
if(d>0) InserT(rt[x],rt[x-1],L);
}
inline int Query(int x,int d){return QuerY(rt[x],d,n+1);}
}B;
inline int calc(int x,int y){
int Res=0;B.clear();
for(int j=1;x<=n;x++,y++,j++){
int k=min(x-U[x][y],y-R[x][y]);
if(k>0)Res+=B.Query(j-1,j)-B.Query(j-k-1,j);
k=min(D[x][y]-x,L[x][y]-y);
B.Insert(j,j+k,k);
}
return Res;
}
int main(){
memset(L,-1,sizeof(L));
memset(D,-1,sizeof(D));
memset(R,0x7F,sizeof(R));
memset(U,0x7F,sizeof(U));
reaD(n);reaD(m);
for(int i=1,x1,y1,x2,y2;i<=m;i++){
reaD(x1);reaD(y1);
reaD(x2);reaD(y2);
if(x1==x2){
if(y1>y2) swap(y2,y1);
for(int j=y1;j<=y2;j++)L[x1][j]=max(y2,L[x1][j]),R[x1][j]=min(y1,R[x1][j]);
}else{
if(x1>x2) swap(x1,x2);
for(int j=x1;j<=x2;j++)D[j][y1]=max(x2,D[j][y1]),U[j][y1]=min(x1,U[j][y1]);
}
}
for(int i=0;i<=n;i++)
for(int j=0,x,y;j<=n;j++)
Sl(i,j),Sd(i,j),
Sr(i,j),Su(i,j);
B.build();
for(int i=0,x,y,j;i<=n;i++)Ans+=calc(i,0)+calc(0,i+1);
return printf("%d\n",Ans),0;
}