题目描述
有 n 个点,一个点集 S 是好的,当且仅当对于他的每个子集 T,存在一个右边无限长的
矩形,使得这个矩形包含了 T,但是和 S-T 没有交
求这 n 个点里有几个好的点集
1<=n<=10^5
思路
当时这题是我队友看的,然后看完题后和我们说,但听不懂,随后他直接想了一个点和两个点的情况,没有想到会有三个点的情况,交了题WA了,然后他怀疑自己读错题目了,然后我们就放弃了。赛后才知道原来没有读错题目,只是漏了一种情况。
官方题解:
对于 |S|=1,他显然是好的
对于 |S|=2,只要两个点的 y 坐标不相同,那么这个集合也是好的
对于 |S|=3,三个点的形状必须是 < 型
对于 |S|>3,不可能任何三个点都是 < 型,所以一定不是好的
用树状数组统计一下就好了
时间复杂度:O(nlogn)
代码如下:
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
using namespace std;
const int mod=998244353;
int tree[400005];
ll n;
int b[100005];
ll box[100005];
struct node
{
int x,y;
bool friend operator <(node w,node e)
{
return w.x>e.x;
}
}a[100005];
void add(int x,int c){
while(x<=n){
tree[x]+=c;
x += x&(-x);
}
}
int sum(int x){
int res = 0;
while(x){
res += tree[x];
x -=x&(-x);
}
return res;
}
int main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[i].x,&a[i].y);
b[i]=a[i].y;
}
sort(b+1,b+1+n);
for(int i=1;i<=n;i++)
{
a[i].y=lower_bound(b+1,b+1+n,a[i].y)-b;
box[a[i].y]++;
}
ll ans=n+n*(n-1)/2;//统计一个点和两个点的情况
for(int i=1;i<=n;i++)
ans-=box[i]*(box[i]-1)/2;//减去两个点有相同的y的情况
ans=(ans+mod)%mod;
int pre=1;
sort(a+1,a+1+n);
for(int i=1;i<=n;i++)
{
ll down=sum(a[i].y-1);
ll up=sum(n)-sum(a[i].y);
ans=(ans+(down*up))%mod;
if(a[i].x!=a[i+1].x){
for(;pre<=i;pre++)
add(a[pre].y,1);
}
}
printf("%lld\n",ans);
return 0;
}