牛客网多校5 I-vcd (树状数组)

题目:有 n 个点,一个点集 S 是好的,当且仅当对于他的每个子集 T,存在一个右边无限长的矩形,使得这个矩形包含了 T,但是和 S-T 没有交求这 n 个点里有几个好的点集 1<=n<=10^5

思路:对于 |S|=1,他显然是好的
对于 |S|=2,只要两个点的 y 坐标不相同,那么这个集合也是好的
对于 |S|=3,三个点的形状必须是   <   型。用树状数组统计,按x从大到小排序,对于一个点,ans+=小于他y坐标的点数*大他要y坐标的点数。
对于 |S|>3,不可能任何三个点都是 < 型,所以一定不是好的。

能读懂题意就好了。。。

取模不是1e9+7啊,

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const ll mod=998244353ll;//取模不是1e9+7!!!
struct node{
    int x,y;
}a[maxn];
int n,tot,b[maxn];
bool cmp(const node &a,const node &b)
{
    return a.x>b.x;
}
int c[maxn];
int lowbit(int x){return x&-x;}
void update(int pos,int val)
{
    while(pos<=n)
    {
        c[pos]+=val;
        pos+=lowbit(pos);
    }
}
int query(int pos)
{
    int ans=0;
    while(pos>0)
    {
        ans+=c[pos];
        pos-=lowbit(pos);
    }
    return ans;
}
int main()
{
    scanf("%d",&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);
    ll ans=0;
    ans+=1ll*n;//1
    (ans+=1ll*(n-1)*n/2)%=mod;//2
    int num=0;
    for(int i=1;i<=n;i++)
    {
        if(b[i]!=b[i-1])
            num=0;
        else num++;
        ans=(ans-1ll*num+mod)%mod;
    }
    tot=unique(b+1,b+n+1)-b-1;
    for(int i=1;i<=n;i++)
        a[i].y=lower_bound(b+1,b+tot+1,a[i].y)-b;
    sort(a+1,a+n+1,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++)//一个x坐标可能有多个y坐标相同的,需要放在一起更新
            update(a[j].y,1);
            last=i;
        }
        int s1=query(a[i].y-1);
        int s2=query(n)-query(a[i].y);
        ans=(ans+1ll*s1*s2)%mod;
    }
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/dllpXFire/article/details/81409222