Portal: QAQQAQ
Topic: Give you N points on the coordinate axis. Ask you the number of different point sets divided by one horizontal line and two vertical lines (excluding empty sets).
Thought: When I don't think clearly, I think it's a water problem: for y-axis sort, then scan from bottom to top to see the number of X different s, ans+=(s+1)*s/2 above, but later I found that this will be repeated to consider some sets, that is, at the current point, these points are sequential about x-axis sort, after deleting this point is still continuous, so we need to subtract these points from y-axis scan. Repeated sets
That is to say, for Y-axis sorting, we scan from top to bottom. For the newly added layer y, we first add (s+1)*s/2, and then find out how many x exists in the gap between them for each x value, minus the repeated set tmp*(tmp+1)/2.
In terms of code implementation, we use line segment tree to maintain x-value L and how many points exist in R interval. When a layer is swept away, we update the original non-existent x-value to 1. If x exists, we don't care about it. We should note that sum maintains the number of different x-axes, not the total number of points.
In updating the answer, for query between two X at the same level, subtract tmp*(tmp+1)/2 from the original number of different x values, and pay attention to sweep both the beginning and the end, and the line segment tree opens to xn+1 in order to prevent crossing the boundary.
Because x, y <= 1e9 can't maintain such a large section directly with the segment tree, and N <= 2e5, we can use common techniques to discretize it.
Code: (I heard that tree array maintenance is more convenient, but I like segment tree ah...)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll N=200005; const ll inf=2000000000; struct node{ ll x,y; bool operator < (const node rhs) const{ if(y==rhs.y) return x<rhs.x; return y>rhs.y; } }a[N]; ll n,x[N],y[N],mx=-inf,vis[N]; struct TREE{ ll sum; }tree[N*4]; void push_up(TREE &fa,TREE ls,TREE rs) { fa.sum=ls.sum+rs.sum; } void build(ll x,ll l,ll r) { if(l==r) { tree[x].sum=0; return; } ll mid=(l+r)>>1; build(x+x,l,mid); build(x+x+1,mid+1,r); push_up(tree[x],tree[x+x],tree[x+x+1]); } void update(ll x,ll l,ll r,ll pos) { if(l==r) { tree[x].sum=1; return; } ll mid=(l+r)>>1; if(pos>mid) update(x+x+1,mid+1,r,pos); if(pos<=mid) update(x+x,l,mid,pos); push_up(tree[x],tree[x+x],tree[x+x+1]); } ll query(ll x,ll l,ll r,ll L,ll R) { if(L>R) return 0; if(L<=l&&r<=R) return tree[x].sum; ll mid=(l+r)>>1; if(mid>=R) return query(x+x,l,mid,L,R); if(mid<L) return query(x+x+1,mid+1,r,L,R); return query(x+x,l,mid,L,R)+query(x+x+1,mid+1,r,L,R); } int main() { scanf("%lld",&n); for(ll i=1;i<=n;i++) { scanf("%lld%lld",&a[i].x,&a[i].y); x[i]=a[i].x; y[i]=a[i].y; } sort(x+1,x+n+1); sort(y+1,y+n+1); ll xn=unique(x+1,x+n+1)-x-1; ll yn=unique(y+1,y+n+1)-y-1; for(ll i=1;i<=n;i++) { a[i].x=lower_bound(x+1,x+xn+1,a[i].x)-x; a[i].y=lower_bound(y+1,y+yn+1,a[i].y)-y; } sort(a+1,a+n+1); build(1,1,xn+1); ll ans=0,sum=0; ll beg=1,now=1; memset(vis,0,sizeof(vis)); while(beg<=n) { ll pre=0; while(a[beg].y==a[now].y&&now<=n) { ll tmp=query(1,1,xn+1,pre+1,a[now].x-1); ans-=tmp*(tmp+1)/2; pre=a[now].x; now++; } ll tmp=query(1,1,xn+1,pre+1,xn); ans-=tmp*(tmp+1)/2; while(beg<now) { if(!vis[a[beg].x]) { sum++; vis[a[beg].x]=1; update(1,1,xn+1,a[beg].x); } beg++; } ans+=(sum+1)*sum/2; } cout<<ans<<endl; return 0; }