https://www.nowcoder.com/acm/contest/143/I
题意:
n个点,一个点集S是好的,当且仅当对于他的每个子集T,存在一个右边无限延长的矩形,使的这个矩形包含了T,但是和S-T没有交集。
求有多少个这种集合。
思路:
对于S=1肯定是个好的集合
对于S=2,只要y坐标不相同也肯定是好的。
对于S=3,三个点的形状必须是 < 型
至于S>3,是不可能存在好的集合的
这样我们可以按照x坐标排序,然后找到比当前y大的和小的各有多少个,再相乘一下就是这以y为中间的种数,对于一个的和两个的可以先算。注意x坐标相同的要一起更新
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e5+10;
const int mod=998244353;
struct node
{
int x,y;
} a[maxn];
ll sum[maxn*4];
bool cmp(node a,node b)
{
return a.x>b.x;
}
vector<int>v;
void update(int l,int r,int k,int x,ll num)
{
if(l==r)
{
sum[x]=(sum[x]+num)%mod;
return ;
}
int mid=(l+r)/2;
if(k<=mid)
update(l,mid,k,x*2,num);
else
update(mid+1,r,k,x*2+1,num);
sum[x]=(sum[x*2]+sum[x*2+1])%mod;
}
ll query(int l,int r,int L,int R,int x)
{
if(L>R)
return 0;
if(L<=l&&R>=r)
{
return sum[x]%mod;
}
ll ans=0;
int mid=(l+r)/2;
if(L<=mid)
ans=(ans+query(l,mid,L,R,x*2))%mod;
if(R>mid)
ans=(ans+query(mid+1,r,L,R,x*2+1))%mod;
return ans;
}
int main()
{
int n;
while(~scanf("%d",&n))
{
v.clear();
memset(sum,0,sizeof(sum));
for(int i=1; i<=n; i++)
{
scanf("%d%d",&a[i].x,&a[i].y);
v.push_back(a[i].y);
}
ll ans=0;
sort(v.begin(),v.end());
ans=(ans+1LL*n)%mod;
ans=(ans+1LL*n*(n-1)/2)%mod;
int cnt=0;
for(int i=0; i<v.size(); i++)
{
if(v[i]!=v[i+1])
cnt=0;
else
cnt++;
ans=(ans-1LL*cnt+mod)%mod;
}
v.erase(unique(v.begin(),v.end()),v.end());
cnt=v.size();
for(int i=1; i<=n; i++)
{
a[i].y=lower_bound(v.begin(),v.end(),a[i].y)-v.begin()+1;
}
sort(a+1,a+1+n,cmp);
int last=1;
for(int i=1; i<=n; i++)
{
if(a[i].x!=a[i-1].x)
{
for(int j=last; j<i; j++)
update(1,cnt,a[j].y,1,1LL);
last=i;
}
ll s1,s2;
s1=query(1,cnt,1,a[i].y-1,1)%mod;
s2=query(1,cnt,a[i].y+1,cnt,1)%mod;
ans=(ans+s1*s2%mod)%mod;
}
printf("%lld\n",ans);
}
return 0;
}