Link.
Description.
给定平面上 \(n(n\le 10^5)\) 个点,问有几种不同的选点方案,使得它能被一个没有上边界的矩形所包含,且其他没有点被这个矩形包含。
Solution.
数数数重了。
首先,我们发现有一个很显然的做法,就是从上往下考虑。
每次把当前这个 \(y\) 坐标的加入后统计答案。
然后刚开始以为这个答案就是 \(\frac{n\times (n+1)}2\),然后发现太 Naive 了。
因为当前这层如果完全不选,答案就在上一层和这一层重复统计了。
所以我们只能考虑对每个数统计答案。
插入一个数后我们需要考虑它可以有多少贡献。
在同一层中,我们强制钦定一个点选且它后面那个点不选,然后相当于统计前面和到下一个点数乘积。
然后直接树状树组维护即可。
Coding.
点击查看ex代码
//是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了{{{
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
x=0;char c=getchar(),f=0;
for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
f?x=-x:x;
}/*}}}*/
int n,xt,yt,X[200005],Y[200005],tn[200005],ut,T[200005];
char vs[200005];vector<int>v[200005];ll rs=0;
inline void add(int x,int w) {for(;x<=xt;x+=x&(-x)) T[x]+=w;}
inline int qry(int x) {int r=0;for(;x;x-=x&(-x)) r+=T[x];return r;}
inline int q(int l,int r) {return qry(r)-qry(l-1);}
int main()
{
read(n);for(int i=1;i<=n;i++) read(X[i]),read(Y[i]);
tn[ut=1]=0;for(int i=1;i<=n;i++) tn[++ut]=X[i];
sort(tn+1,tn+ut+1),xt=ut=unique(tn+1,tn+ut+1)-tn-1;
for(int i=1;i<=n;i++) X[i]=lower_bound(tn+1,tn+ut+1,X[i])-tn;
tn[ut=1]=0;for(int i=1;i<=n;i++) tn[++ut]=Y[i];
sort(tn+1,tn+ut+1),yt=ut=unique(tn+1,tn+ut+1)-tn-1;
for(int i=1;i<=n;i++) Y[i]=lower_bound(tn+1,tn+ut+1,Y[i])-tn;
for(int i=1;i<=yt;i++) v[i].push_back(1);
for(int i=1;i<=n;i++) v[Y[i]].push_back(X[i]);
for(int i=1;i<=yt;i++) v[i].push_back(xt+1);
for(int i=yt;i>=1;i--)
{
sort(v[i].begin(),v[i].end());
//{for(auto x:v[i]) printf("%d ",x);putchar('\n');}
for(int j=1;j<(int)v[i].size()-1;j++)
{
if(!vs[v[i][j]]) add(v[i][j],1),vs[v[i][j]]=1;
rs+=1ll*q(1,v[i][j])*q(v[i][j],v[i][j+1]-1);
//printf("%d,%d : %d*%d\n",i,v[i][j],q(1,v[i][j]),q(v[i][j],v[i][j+1]-1));
}
}
return printf("%lld\n",rs),0;
}