luogu 3415 祭坛
题目大意:
在平面上,有 n 个水晶柱,每个水晶柱可以用一个点表示
如果 4 个水晶柱依次相连可以构成一个四边形,满足其两条对角线分别平行于 x 轴和 y 轴,并且对角线的交点位于四边形内部(不包括边界)
那么这 4 个水晶柱就可以建立一个结界
其中,对角线的交点称作这个结界的中心
例如下左图中,水晶柱 ABCD 可以建立一个结界,其中心为 O
人们会把祭坛修建在最多层结界的保护中
其中不同层的结界必须有共同的中心,这些结界的边界不能有任何公共点,并且中心处也不能有水晶柱
这里共同中心的结界数量叫做结界的层数
为了达成这个目的,人们要先利用现有的水晶柱建立若干个结界,然后在某些结界的中心建立祭坛
例如上右图中,黑色的点表示水晶柱(注意 P 和 O 点不是水晶柱)。祭坛的一个最佳位置为 O 点,可以建立在 3 层结界中,其结界的具体方案见下左
当然,建立祭坛的最佳位置不一定是唯一,在上右图中,O 点左侧 1 单位的点 P 也可以建立一个在 3 层结界中的祭坛,见下右图
现在人们想知道:祭坛最佳选址地点所在的结界层数以及祭坛最佳的选址地点共有多少个
思路:
首先可以二分一下答案
然后对于每一个满足条件的点在它的上下左右四个方向一定有至少mid个点
对于上下或者左右是否满足条件 可以直接求出这个区间
对于另一个方向 使用扫描线与树状数组维护
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<cstring> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #define inf 2139062143 10 #define ll long long 11 #define MAXN 100100 12 using namespace std; 13 inline int read() 14 { 15 int x=0,f=1;char ch=getchar(); 16 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 17 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 18 return x*f; 19 } 20 int n,up[MAXN],dn[MAXN],q[MAXN],cnt; 21 vector<int> vec[MAXN]; 22 int c[MAXN],hsh[MAXN]; 23 int lowbit(int x) {return x&(-x);} 24 void add(int x,int val) {for(int i=x;i<=n;i+=lowbit(i)) c[i]+=val;} 25 int query(int x) {int res=0;for(int i=x;i;i-=lowbit(i)) res+=c[i];return res;} 26 int check(int x) 27 { 28 int res=0,t; 29 memset(hsh,0,sizeof(hsh)); 30 memset(c,0,sizeof(c)); 31 memset(up,0,sizeof(up)); 32 memset(dn,0,sizeof(dn)); 33 for(int i=1;i<=cnt;i++) 34 for(int j=0;j<vec[q[i]].size();j++) dn[vec[q[i]][j]]++; 35 for(int k=1;k<=cnt;k++) 36 { 37 t=q[k]; 38 for(int i=0;i<vec[t].size();i--) 39 { 40 dn[vec[t][i]]--; 41 if((dn[vec[t][i]]<x||up[vec[t][i]]<x)&&hsh[vec[t][i]]) 42 hsh[vec[t][i]]=0,add(vec[t][i],-1); 43 } 44 if(x-1<vec[t].size()) 45 { 46 int l=vec[t][x-1],r=vec[t].size()-x; 47 if(r<0) goto ed; 48 r=vec[t][r]; 49 if(r>0&&l<=r-1) res+=query(r-1)-query(l); 50 }ed:; 51 for(int i=0;i<vec[t].size();i--) 52 { 53 up[vec[t][i]]++; 54 if(dn[vec[t][i]]>=x&&up[vec[t][i]]>=x&&!hsh[vec[t][i]]) {hsh[vec[t][i]]=1,add(vec[t][i],1);} 55 } 56 } 57 return res; 58 } 59 int main() 60 { 61 n=read();int a,b; 62 for(int i=1;i<=n;i++) 63 { 64 a=read(),b=read(); 65 vec[a].push_back(b); 66 q[++cnt]=a; 67 } 68 sort(q+1,q+cnt+1); 69 cnt=unique(q+1,q+cnt+1)-q-1; 70 for(int i=1;i<=cnt;i++) sort(vec[q[i]].begin(),vec[q[i]].end()); 71 int l=1,r=n,ans=0,res=0; 72 while(l<=r) 73 { 74 int mid=l+r>>1; 75 if(a=check(mid)) ans=mid,l=mid+1,res=a; 76 else r=mid-1; 77 } 78 printf("%d\n%d",ans,res); 79 }