zoukankan      html  css  js  c++  java
  • codeforces1190D Tokitsukaze and Strange Rectangle 线段树(树状数组)扫描线+计数

    网址:http://codeforces.com/problemset/problem/1190/D

    题意:

    给出平面直角坐标系下的点,使用一个上不封顶的矩形把某些点围住作为一个集合,两个集合不同只要数量不同或者数量相同时存在一个点不同,集合必须非空,求这样的集合的数量。

    题解:

    扫描线法:对$y$轴自顶向下,对于其中一层$y_i$,有以下$n$个点,坐标是$x_1,x_2,x_3......x_n$,以递增序排列,在某一时候,$x_i$加入序列,$y_i$层之前已经计数的矩形不受影响,增加的是加入了新的点之后可构成的新矩形。所以以这个点作为新点,统计加入前的矩形。为了保证有边界,左边界取$1$,有边界取$x$轴的最大值$+1$。则由计数原理,不同的矩形只要存在一条边界不同即可,点数$=$边数$-1$,故矩形数$=$这个点(左边点数$+1)$$*$$($右边点数$+1)$。由于同一个横坐标的值的点等价,对于纵坐标更小而横坐标相同的点,因为已经计算它上面的点,所以其不能和纵坐标大的点累加,故扫描时直接覆盖而不是累加。

    然后是技巧,这个题的的数据范围是$2e5$,所以需要数据结构优化,然后坐标值范围是$1e9$,所以需要离散化。

    AC代码:

    (线段树)

    #include <iostream>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #pragma GCC optimize(2)
    using namespace std;
    struct Point
    {
        int x,y;
        bool operator<(const Point &a)const
        {
            return y==a.y?x<a.x:y>a.y;
        }
    };
    Point p[200005];
    int x[200005],y[2000005];
    struct Segtree
    {
        struct node
        {
            int l,r;
            int v;
        }tr[200005*4];
        void build(int l,int r,int k)
        {
            tr[k].l=l,tr[k].r=r;
            if(l==r)
            {
                tr[k].v=0;
                return;
            }
            int m=(l+r)/2;
            build(l,m,k*2);
            build(m+1,r,k*2+1);
            tr[k].v=tr[k*2].v+tr[k*2+1].v;
        }
        void update(int pos,int k,int val)//单点修改
        {
            if(tr[k].l==tr[k].r)
            {
                tr[k].v=val;
                return;
            }
            int m=(tr[k].l+tr[k].r)/2;
            if(pos<=m)
                update(pos,k*2,val);
            else if(pos>m)
                update(pos,k*2+1,val);
            tr[k].v=tr[k*2].v+tr[k*2+1].v;
        }
        int query(int l,int r,int k)
        {
            if(l>r)
                return 0;
            if(l<=tr[k].l&&r>=tr[k].r)
            {
                return tr[k].v;
            }
            int m=(tr[k].l+tr[k].r)/2;
            //cout<<tr[k].l<<" "<<tr[k].r<<endl;
            int ans=0;
            if(l<=m)
                ans+=query(l,r,k*2);
            if(r>m)
                ans+=query(l,r,k*2+1);
            return ans;
        }
    };
    Segtree seg;
    int ydiv[200005];
    int main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);
        int n;
        cin>>n;
        for(int i=0;i<n;++i)
        {
            cin>>x[i]>>y[i];
            p[i].x=x[i];
            p[i].y=y[i];
        }
        sort(x,x+n);
        sort(y,y+n);
        int xnew=unique(x,x+n)-x;
        int ynew=unique(y,y+n)-y;
        for(int i=0;i<n;++i)
        {
            p[i].x=lower_bound(x,x+xnew,p[i].x)-x+1;
            p[i].y=lower_bound(y,y+ynew,p[i].y)-y+1;
            //cout<<p[i].x<<" "<<p[i].y<<endl;
        }
        sort(p,p+n);
        //扫描线
        seg.build(1,xnew+1,1);
        int beg=0,cur=0;
        long long sum=0;
        while(beg<n)
        {
            int pos=0;
            while(cur<n&&p[cur].y==p[beg].y)
            {
                seg.update(p[cur].x,1,1);
                ydiv[pos++]=p[cur++].x;
            }
            ydiv[pos]=xnew+1;
            for(int i=0;i<pos;++i)
            {
                long long cntl=seg.query(1,ydiv[i]-1,1);
                long long cntr=seg.query(ydiv[i]+1,ydiv[i+1]-1,1);
                sum+=(cntl+1)*(cntr+1);
            }
            beg=cur;
        }
        cout<<sum<<endl;
        return 0;
    }
    

    (树状数组)

    注:单点修改时,因为每个横坐标值最多只会同时有一个点(被覆盖),所以已经修改成$1$的地方,再需要修改时,也是覆盖成1,所以直接用一个$vis$数组记录是否已经修改。

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #pragma GCC optimize(2)
    using namespace std;
    struct Fenwick
    {
        bool cntx[200005];
        int c[200005];
        int lowbit(int x)
        {
            return x&(-x);
        }
        void update(int pos,int val,int n)//Containing error
        {
            if(cntx[pos])
                return;
            else
            {
                cntx[pos]=1;
                for(int i=pos;i<=n;i+=lowbit(i))
                    c[i]+=val;
            }
        }
        int sum(int pos,int n)
        {
            int sum=0;
            for(int i=pos;i;i-=lowbit(i))
                sum+=c[i];
            return sum;
        }
        int query(int l,int r,int n)
        {
            if(l>r)
                return 0;
            return sum(r,n)-sum(l-1,n);
        }
        void print(int n)
        {
            for(int i=0;i<n;++i)
                cout<<c[i]<<" ";
            cout<<endl;
        }
    };
    struct Point
    {
        int x,y;
        bool operator<(const Point &a)const
        {
            return y==a.y?x<a.x:y>a.y;
        }
    };
    Point p[200005];
    int x[200005],y[200005],ydiv[200005];
    Fenwick tr;
    int main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);
        int n;
        cin>>n;
        for(int i=0;i<n;++i)
        {
            cin>>x[i]>>y[i];
            p[i].x=x[i];
            p[i].y=y[i];
        }
        sort(x,x+n);
        sort(y,y+n);
        int xn=unique(x,x+n)-x;
        int yn=unique(y,y+n)-y;
        for(int i=0;i<n;++i)
        {
            p[i].x=lower_bound(x,x+xn,p[i].x)-x+1;
            p[i].y=lower_bound(y,y+yn,p[i].y)-y+1;
            //cout<<p[i].x<<" "<<p[i].y<<endl;
        }
        sort(p,p+n);
        //扫描线
        memset(tr.c,0,sizeof(tr.c));
        int beg=0,cur=0;
        //max xn+1
        long long sum=0;
        while(beg<n)
        {
            int pos=0;
            while(cur<n&&p[cur].y==p[beg].y)
            {
                tr.update(p[cur].x,1,xn+1);
                ydiv[pos++]=p[cur++].x;
                //tr.print(xn+1);
            }
            ydiv[pos]=xn+1;
            for(int i=0;i<pos;++i)
            {
                long long cntl=tr.query(1,ydiv[i]-1,xn+1);
                long long cntr=tr.query(ydiv[i]+1,ydiv[i+1]-1,xn+1);
                sum+=(cntl+1)*(cntr+1);
            }
            beg=cur;
        }
        cout<<sum<<endl;
        return 0;
    }
    
  • 相关阅读:

    转:在自己的工具条中使用ArcGIS Engine提供的命令和工具
    配置Subversion Apache TortoiseSVN
    vc++2005移除自定义向导目录
    NetAdvantage2006 For ASP.NET2.0印象
    三天了!今天终于成功安装ArcIMS9.2!
    vss 去除源代码管理
    转:设计模式趣谈
    转一篇:有关项目报告
    演练:使用 Visual Studio Team Test 进行单元测试
  • 原文地址:https://www.cnblogs.com/Aya-Uchida/p/11185312.html
Copyright © 2011-2022 走看看