https://jzoj.net/senior/#main/show/3195
首先吐槽一下搬题人。你搬题就搬嘛,还非要搞点别的,原题的 x , y x,y x,y互不相同,这里可以相同,并且,矩形还可以是就一行或者就一列的,数据又水,50分根本发现不出来,结果调了好久才发现暴力都是错的。
经典套路就是分治了。
但是注意,为了不算重并且更好打,我们应该按值来分治,不要按序列来分治。分治完之后我们注意到,左边维护一个 y y y递减的情况下满足 x x x递减的单调栈,右边维护一个 y y y体检的情况下 x x x递增的一个单调栈。然后每次lower_bound一下可以找到合法的一段区间,统计答案即可。
细节很多,注意特殊处理在同一行和同一列的情况。
#include
#define F(i,a,b) for(int i=a;i<=(b);i++)
const int N=1e5+10;
using namespace std;
int lx[N],ly[N],rx[N],ry[N];
int n,MN,MX,Ans,dw,up,cnt,lasx,lasy;
struct node{int x,y;}d[N],Lef[N],Rig[N];
bool cmx(node a,node b) {return a.x<b.x||a.x==b.x&&a.y<b.y;}
bool cmy1(node a,node b) {return a.y>b.y||a.y==b.y&&a.x>b.x;}
bool cmy2(node a,node b) {return a.y>b.y||a.y==b.y&&a.x<b.x;}
int Find(int x,int y,int r,int n){
int l=1, Ans=0;
while(l<=r){
int m=l+r>>1;
if ((!y&&ly[m]>=x&&lx[m]<n)||(y&&ry[m]>=x&&rx[m]>n)) Ans=m, l=m+1; else r=m-1;
}
return Ans;
}
void CDQ(int ll,int rr,int l,int r){
if(ll>=rr||l>=r)return;
int mm=ll+rr>>1,m=l+r>>1,L=0,R=0,LL=1,RR=1;
while(d[m].x>mm)m--;
while(d[m+1].x<=mm)m++;
F(i,l,m) Lef[++L]=d[i];
F(i,m+1,r) Rig[++R]=d[i];
if (L==0||R==0) {CDQ(ll,mm,l,m),CDQ(mm+1,rr,m+1,r);return;}
sort(Lef+1,Lef+L+1,cmy1);
sort(Rig+1,Rig+R+1,cmy2);
F(i,2,L)
if (Lef[i].y^Lef[LL].y) Lef[++LL]=Lef[i];
F(i,2,R)
if (Rig[i].y^Rig[RR].y) Rig[++RR]=Rig[i];
if(LL==0||RR==0)return;
L=R=0,Lef[++LL]={-1e9,-1e9};
for (int i=1,j=1;i<=LL;i++){
while(j<=RR&&Rig[j].y>=Lef[i].y){
if (Rig[j].y==Lef[i].y)
while(L&&Lef[i].x>=lx[L]) L--;
lasx=lasy=1e9;
while(R&&Rig[j].x<=rx[R]) {
if (Rig[j].x==rx[R]) lasy=ry[R], lasx=rx[R];
R--;
}
if (lasy==1e9)
lasx=rx[R], lasy=ry[R];
rx[++R]=Rig[j].x, ry[R]=Rig[j].y;
dw=Find(ry[R],0,L,rx[R]), up=Find(lasy,0,L,lasx);
if (ly[dw]==ry[R]) dw--;
Ans+=dw-up;
j++;
}
if (i==LL) break;
lasy=1e9;
while(L&&Lef[i].x>=lx[L]) {
if (Lef[i].x==lx[L]) lasy=ly[L];
L--;
}
if (lasy==1e9)
lasy=ly[L];
lx[++L]=Lef[i].x, ly[L]=Lef[i].y;
dw=Find(ly[L],1,R,lx[L]), up=Find(lasy,1,R,-1e9);
if (ry[dw]==ly[L]) dw--;
Ans+=dw-up;
}
F(i,1,max(LL,RR)) rx[i]=ry[i]=lx[i]=ly[i]=0;
CDQ(ll,mm,l,m),CDQ(mm+1,rr,m+1,r);
}
int main(){
scanf("%d",&n),ry[0]=ly[0]=MN=1e9;
F(i,1,n) scanf("%d%d",&d[i].x,&d[i].y),MN=min(MN,d[i].x),MX=max(MX,d[i].x);
sort(d+1,d+n+1,cmx);
F(i,1,n)
if(d[i].x==d[i+1].x) cnt++;
else Ans+=cnt, cnt=0;
CDQ(MN,MX,1,n);
sort(d+1,d+n+1,cmy1);
F(i,1,n)
if(d[i].y==d[i-1].y) cnt++;
else Ans+=cnt, cnt=0;
printf("%d\n",Ans+cnt);
}