牛客多校第五场 I vcd(树状数组)

链接:https://www.nowcoder.com/acm/contest/143/I
来源:牛客网
 

题目描述

Kanade has an infinity set H contain all of sets such as {(x,y)|x>=a,l<=y<=r}  (a,l,r are arbitrary real numbers)

A point set S is good if and only if for each subset T of S there exist h in H satisfy 

Now kanade has n distinct points and she want to know how many non-empty subset of these points is good.

You need to output the answer module 998244353

输入描述:

The first line has one integer n

Then there are n lines,each line has two integers x,y denote a point (x,y)

输出描述:

Output the answer module 998244353

示例1

输入

复制

3
1 1
2 2
3 3

输出

复制

6

题目大意:题目中定义如果一个点集|S|是好的,那么这个点集内的任意一个子点集|T|都可以被一个右边无限长的矩形所覆盖,但是除了这个子点集以外的点都不会被这个矩形覆盖。现在给你二维平面内的n个点,问你一共有多少个点集是好的。

题目思路:先讨论点集S中只有一个点的情况,很明显任意一个只有一个点的点集都是好的。

再讨论点集S中有两个点的情况,我们可以发现只要两个点的y坐标不同,那么这个点集也是好的。因为如果两个点的y坐标是相同的话,以x坐标较小的点单独作为这个点集的子点集时,无论怎么取矩形,右侧都是会覆盖到x坐标较大的点。

接着讨论点集S中有三个点的情况,通过观察发现只有三个点呈现类似 “<” 的形状的时候才能满足题目的条件,其它情况下,都会有一个子点集用矩形覆盖时会覆盖到其它的点。

继续讨论点集S中有大于三个点的情况,我们发现任意三个点无法都形成 “<”的形状,故大于三个点的点集都不是好的点集。

点集|S|中只有一个点和两个点的情况还是很好处理的,对于有三个点的情况,我们可以通过一个树状数组来进行维护。

我们将所有的点的坐标离散化之后按照x坐标从小到大排序。然后倒着将每一个点按y坐标插入树状数组中,每次找出当前点的左上方有多少个点,右下方有多少个点,即可统计出答案。

具体实现看代码:

#include <bits/stdc++.h>
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lowbit(x) x&-x
#define pb push_back
#define MP make_pair
#define clr(a) memset(a,0,sizeof(a))
#define _INF(a) memset(a,0x3f,sizeof(a))
#define FIN freopen("in.txt","r",stdin)
#define fuck(x) cout<<"["<<x<<"]"<<endl
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>pii;
typedef vector<int> VI;
const int MX=1e5+5;
const int mod=998244353;
const int inf=0x3f3f3f3f;
//head

int n;
struct Point{
	int x,y;
	ll up,down;
}a[MX];
bool cmp1(Point A,Point B){
	if(A.x==B.x) return A.y<B.y;
	return A.x<B.x;
}
bool cmp2(Point A,Point B){
	if(A.x==B.x) return A.y>B.y;
	return A.x<B.x;
}
VI has;
int get_id(int x){
	return lower_bound(has.begin(),has.end(),x)-has.begin()+1;
}
ll bit[MX];
void add(int x,ll d){
	for(int i=x;i<=n;i+=lowbit(i))
		bit[i]+=d;
}
ll sum(int x){
	ll res=0;
	for(int i=x;i;i-=lowbit(i))
		res+=bit[i];
	return res;
}
ll num[MX];

int main(){
	//FIN;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d%d",&a[i].x,&a[i].y);
		has.pb(a[i].y);
	}
	sort(has.begin(),has.end());
	has.erase(unique(has.begin(),has.end()),has.end());
	sort(a+1,a+n+1,cmp1);
	for(int i=n;i>=1;i--){
		int idy=get_id(a[i].y);num[idy]++;
		a[i].up=sum(idy-1);
		add(idy,1);
	}
	sort(a+1,a+n+1,cmp2);
	clr(bit);
	for(int i=n;i>=1;i--){
		int idy=get_id(a[i].y);
		a[i].down=sum(n)-sum(idy);
		add(idy,1);
	}
	ll ans=(n+(ll)n*(n-1)/2)%mod;
	for(int i=1;i<=n;i++){
		ans=(ans-num[i]*(num[i]-1)/2+mod)%mod;
		ans=(ans+a[i].up*a[i].down)%mod;
	}
	printf("%lld\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Lee_w_j__/article/details/81381013