codeforces 1190D-Tokitsukaze and Strange Rectangle

传送门:QAQQAQ

题意:给你在坐标轴上的N个点,问你用一条横线和两条竖线所划分出的不同点集的个数(不包括空集)

思路:在没想清楚的时候觉得这是一道水题:对于y轴排序,然后从下往上扫看上方x不同的个数s,ans+=(s+1)*s/2即可,但后来发现这样会重复考虑一些集合,即在当前点时这几个点关于x轴排序是连续的,删掉这个点后仍是连续的,所以我们在对于y轴扫描时要减去这些重复的集合

即我们对于Y轴排序,从上至下扫描,对于当前新加入的一层y,先加上(s+1)*s/2,再对于每一个x值寻找它们之间的空隙中原本存在了多少x,减去这些重复的集合tmp*(tmp+1)/2即可

在代码实现方面,我们用线段树维护x值l,r区间内现存在多少点,每当一层扫完,把原先不存在的x值update成1,若x存在就不要管它,注意sum维护的是当前不同的x轴的个数,而不是总点数

在更新答案方面,对于同一层的两个x之间query一下原有不同x值个数,减一下tmp*(tmp+1)/2即可,注意开头和结尾都要扫,而且线段树开到xn+1是为了防止越界

因为x,y<=1e9无法直接用线段树维护这么大一段区间,而n<=2e5,所以我们用常用技巧离散化一下即可

代码:(听说树状数组维护更方便,但我喜欢线段树啊……

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=200005;
const ll inf=2000000000;
 
struct node{
    ll x,y;
    bool operator < (const node rhs) const{
        if(y==rhs.y) return x<rhs.x;
        return y>rhs.y;
    }
}a[N];
 
ll n,x[N],y[N],mx=-inf,vis[N];
 
struct TREE{
    ll sum;
}tree[N*4];
 
void push_up(TREE &fa,TREE ls,TREE rs)
{
    fa.sum=ls.sum+rs.sum;
}
 
void build(ll x,ll l,ll r)
{
    if(l==r) 
    {
        tree[x].sum=0;
        return;
    }
    ll mid=(l+r)>>1;
    build(x+x,l,mid);
    build(x+x+1,mid+1,r);
    push_up(tree[x],tree[x+x],tree[x+x+1]);
}
 
void update(ll x,ll l,ll r,ll pos)
{
    if(l==r)
    {
        tree[x].sum=1;
        return;
    }
    ll mid=(l+r)>>1;
    if(pos>mid) update(x+x+1,mid+1,r,pos);
    if(pos<=mid) update(x+x,l,mid,pos);
    push_up(tree[x],tree[x+x],tree[x+x+1]);
}
 
ll query(ll x,ll l,ll r,ll L,ll R)
{
    if(L>R) return 0;
    if(L<=l&&r<=R) return tree[x].sum;
    ll mid=(l+r)>>1;
    if(mid>=R) return query(x+x,l,mid,L,R);
    if(mid<L) return query(x+x+1,mid+1,r,L,R);
    return query(x+x,l,mid,L,R)+query(x+x+1,mid+1,r,L,R);
}
 
int main()
{
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++) 
    {
        scanf("%lld%lld",&a[i].x,&a[i].y);
        x[i]=a[i].x; y[i]=a[i].y;
    }
    sort(x+1,x+n+1); sort(y+1,y+n+1);
    ll xn=unique(x+1,x+n+1)-x-1;
    ll yn=unique(y+1,y+n+1)-y-1;
    for(ll i=1;i<=n;i++)
    {
        a[i].x=lower_bound(x+1,x+xn+1,a[i].x)-x;
        a[i].y=lower_bound(y+1,y+yn+1,a[i].y)-y;
    }
    sort(a+1,a+n+1);
    build(1,1,xn+1);
    ll ans=0,sum=0;
    ll beg=1,now=1;
    memset(vis,0,sizeof(vis));
    while(beg<=n)
    {
        ll pre=0;
        while(a[beg].y==a[now].y&&now<=n)
        {
            ll tmp=query(1,1,xn+1,pre+1,a[now].x-1);
            ans-=tmp*(tmp+1)/2;
            pre=a[now].x;
            now++;
        }
        ll tmp=query(1,1,xn+1,pre+1,xn);
        ans-=tmp*(tmp+1)/2;
        while(beg<now)
        {
            if(!vis[a[beg].x])
            {
                sum++;
                vis[a[beg].x]=1;
                update(1,1,xn+1,a[beg].x);
            }
            beg++;
        }
        ans+=(sum+1)*sum/2;
    }
    cout<<ans<<endl;
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/Forever-666/p/11253460.html