• 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
  • 相关阅读:
    分治法求最大子序列
    6.2 链表 (UVa 11988, 12657)
    6.1 栈和队列 (UVa 210, 514, 442)
    S-Tree (UVa 712) 二叉树
    Equilibrium Mobile (UVa 12166) dfs二叉树
    Patrol Robot (UVa 1600) BFS
    Knight Moves (UVa 439) BFS
    Tree Recovery (UVa 536) 递归遍历二叉树
    Parentheses Balance (Uva 673) 栈
    Self-Assembly (UVa 1572)
  • 原文地址:https://www.cnblogs.com/Forever-666/p/11253460.html
Copyright © 2020-2023  润新知