Newcoder 143 I.vcd(BIT)

Description

一个点集 S S S是合法的当且仅当对该集合的每个子集 T T T,都存在三元组 ( a , l , r ) (a,l,r) (a,l,r),使得 h ( a , l , r ) ∩ S = T h(a,l,r)\cap S=T h(a,l,r)S=T,其中 h ( a , l , r ) = { ( x , y ) ∣ x ≥ a , l ≤ y ≤ r } h(a,l,r)=\{(x,y)|x\ge a,l\le y\le r\} h(a,l,r)={(x,y)xa,lyr}

给出 n n n个点组成的点集,找出其合法非空子集个数

Input

第一行一整数 n n n表示点数,之后 n n n行每行输入一个点的横纵坐标 x , y x,y x,y

( 1 ≤ n ≤ 1 0 5 , 1 ≤ x , y ≤ 1 0 9 ) (1\le n\le 10^5,1\le x,y\le 10^9) (1n105,1x,y109)

Output

输出所给点集的合法子集个数,结果模 998244353 998244353 998244353

Sample Input

3
1 1
2 2
3 3

Sample Output

6

Solution

1.单点集必然可以,方案数 n n n

2.两个点的点集,若两点纵坐标相同则不行,其他情况都可以,统计纵坐标为 i i i出现的次数 n u m i num_i numi,那么方案数为 C n 2 − ∑ C n u m i 2 C_n^2-\sum C_{num_i}^2 Cn2Cnumi2

3.三个点的点集,三点纵坐标均不能相同,且有一点横坐标需要严格小于另外两点横坐标,假设三点坐标为 ( x 1 , y 1 ) , ( x 2 , y 2 ) , ( x 3 , y 3 ) (x_1,y_1),(x_2,y_2),(x_3,y_3) (x1,y1),(x2,y2),(x3,y3),那么有 x 1 &lt; x 2 , x 3 , y 2 &lt; y 1 &lt; y 3 x_1&lt;x_2,x_3,y_2&lt;y_1&lt;y_3 x1<x2,x3,y2<y1<y3,考虑 ( x 1 , y 1 ) (x_1,y_1) (x1,y1)对答案的贡献,即为所有横坐标大于 x 1 x_1 x1,纵坐标大于 y 1 y_1 y1的点的个数乘上横坐标大于 x 1 x_1 x1,纵坐标小于 y 1 y_1 y1的点的个数,将所有点按横坐标从大到小排序,将纵坐标插入树状数组中计数即可

4.超过三个点的点集无解

Code

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
#define maxn 100005
struct BIT 
{
	#define lowbit(x) (x&(-x))
	int b[maxn],n;
	void init(int _n)
	{
		n=_n;
		for(int i=1;i<=n;i++)b[i]=0;
	}
	void update(int x,int v)
	{
		while(x<=n)
		{
			b[x]+=v;
			x+=lowbit(x);
		}
	}
	int query(int x)
	{
		int ans=0;
		while(x)
		{
			ans+=b[x];
			x-=lowbit(x);
		}
		return ans;
	}
}bit;
P a[maxn];
int n,h[maxn],num[maxn];
#define x first
#define y second
#define mod 998244353
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&a[i].x,&a[i].y);
		h[i-1]=a[i].y;
	}
	sort(h,h+n);
	int m=unique(h,h+n)-h;
	for(int i=1;i<=n;i++)
	{
		a[i].y=lower_bound(h,h+m,a[i].y)-h+1;
		num[a[i].y]++;
	}
	bit.init(m);
	sort(a+1,a+n+1);
	ll ans=n+1ll*n*(n-1)/2;
	for(int i=1;i<=m;i++)ans-=1ll*num[i]*(num[i]-1)/2;
	for(int i=n;i>=1;i--)
	{
		int j=i;
		while(j>=1&&a[j].x==a[i].x)j--;
		j++;
		for(int k=j;k<=i;k++)
			ans+=1ll*(bit.query(m)-bit.query(a[k].y))*bit.query(a[k].y-1);
		for(int k=j;k<=i;k++)bit.update(a[k].y,1);
		i=j;
	}
	printf("%lld\n",ans%mod);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值