F. Tokitsukaze and Strange Rectangle(树状数组+离散化)

题目链接:哆啦A梦传送门

题意:二维平面上有n个点,定义一个奇怪的矩形,它是以 l=<x,x<=r,y>=a,每个这样的矩形包含了一些点,问:有多少个不同的矩形。两个矩形不同当且仅当至少有一个点不同。

 

题解:

我们先按y从大到小排,x从小到大。这样我们就相当于有一条扫描线,从上往下扫。

每到一条扫描线,我们会增加t个新点,我们以添加的每个新点i为结束的集合。此时我们只需分别计算 [1,i-1]和 [i+1,j-1] (j表示同一条扫描线新点i的下一个新点j)的旧点数量为t1,t2。那么就说明新点i左边有t1+1条竖直线,右边有t2+1条竖直线,此时方案数就为(t1+1)*(t2+1)。

依次类推整条扫描线的其它新点。

例如:我们看下副图,当新点A加进去后,A点左右边分别有1,2个点,也就是分别有2,3条线,显然此时有2*3中集合。

这里以A点时算它右边点时,就没有算上B点,因为之后我们算B点时他会算上A点,我们这样做也是为了去重。

 

#include<cstdio>
#include<algorithm>
#include<cstring>

using namespace std;

typedef long long LL;

const int N=2e5+10;
struct node{
    int x,y;
    bool operator<(const node &p)const{
        return y==p.y?x<p.x:y>p.y;
    }
}num[N];

int X[N];

bool vis[N];
int tree[N];
int up;

inline int sum(int x)
{
    int res=0;
    while(x){
        res+=tree[x];
        x-=x&-x;
    }
    return res;
}

inline void update(int x)
{
    while(x<=up){
        tree[x]+=1;
        x+=x&-x;
    }
}

inline q_sum(int x,int y)
{
    return sum(y)-sum(x-1);
}


int vx[N];

int main()
{

    int n;
    scanf("%d",&n);

    for(int i=1;i<=n;i++){
        scanf("%d%d",&num[i].x,&num[i].y);
        X[i]=num[i].x;
    }
    sort(X+1,X+1+n);

    int cnt=unique(X+1,X+1+n)-(X+1);

    ///离散化x值
    for(int i=1;i<=n;i++){
        num[i].x=lower_bound(X+1,X+1+cnt,num[i].x)-X;
    }

    sort(num+1,num+1+n);
    LL ans=0;
    up=cnt+1;

    ///now当前扫描线的第一个点,next当前扫描线的其他点
    int now=1,next=1;

    while(now<=n)
    {
        int tot=0;
        while(num[now].y==num[next].y){
                if(!vis[num[next].x]) ///已经加过了,就不用再加了
            update(num[next].x);
            vis[num[next].x]=1;
            vx[++tot]=num[next].x;
            next++;
        }

        vx[++tot]=cnt+1;

        for(int i=1;i<=tot-1;i++)
        {
            ///计算以当前新点为结束的左,右分别有多少个旧点
            int t1=q_sum(1,vx[i]-1);
            int t2=q_sum(vx[i]+1,vx[i+1]-1);
            ans+=1LL*(t1+1)*(t2+1);
        }
        now=next;

    }

    printf("%lld\n",ans);


    return 0;
}

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值