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

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

时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

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

备注:

1<=n<=10^5

1<=x, y<=10^9

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

思路:

对于 |S|=1,他显然是好的
对于 |S|=2,只要两个点的 y 坐标不相同,那么这个集合也是好的
对于 |S|=3,三个点的形状必须是 < 型
对于 |S|>3,不可能任何三个点都是 < 型,所以一定不是好的

所以需要特殊处理的就是形如<的点集,我们可以把坐标按照x从大到小排序,然后以y坐标的值挨个插入树状数组当中,要注意y坐标最大值有10^9,所以要先离散化处理y坐标然后再插入,要注意的是如果x坐标相同的点需要全部插入后再求sum,那么对于一个点来说,形如<的点集的个数就是(y坐标比它小的点数)*(y坐标比它大的点数),最后输出和即可。(不知道为啥n不开longlong就会WA)

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
const int mod=998244353;
typedef long long ll;
int b[maxn];
ll q[maxn];
ll c[maxn];
struct node
{
    int x,y;
    bool operator<(const node &a)const
    {
        return x>a.x;
    }
}a[maxn];

int lowbit(int x)
{
    return x&(-x);
}
void add(int p,ll v)
{
    while(p<=maxn)
    {
        c[p]+=v;
        p+=lowbit(p);
    }
}
ll sum(int p)
{
    ll res=0;
    while(p)
    {
        res+=c[p];
        p-=lowbit(p);
    }
    return res;
}
int main()
{
    ll n;
    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+n+1);
    for(int i=1;i<=n;i++)
    {
        a[i].y=lower_bound(b+1,b+n+1,a[i].y)-b;//离散化处理y坐标
        q[a[i].y]++;
    }
    ll ans=(n+n*(n-1)%mod/2)%mod;//只含有一个和两个点的点集个数
    for(int i=1;i<=n;i++)
        ans-=(q[i]*(q[i]-1)%mod/2)%mod;//消除y坐标相同的点对答案的影响
    int t=1;
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++)
    {
        ll down=sum(a[i].y-1);//y坐标更小的点数
        ll up=sum(n)-sum(a[i].y);//y坐标更大的点数
        ans=(ans+(up*down))%mod;
        if(a[i].x!=a[i+1].x)//x坐标相同的点要一次性插入
        {
            while(t<=i) add(a[t].y,1),t++;
        }
    }
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/baymax520/article/details/81485430