zoukankan      html  css  js  c++  java
  • Codeforces 1194E. Count The Rectangles

    传送门

    看到 $n<=5000$,直接暴力枚举左右两条竖线

    然后考虑怎么计算高度在某个范围内,左端点小于等于某个值,右端点大于等于某个值的横线数量

    直接用权值树状数组维护当前高度在某个区间内的横线数量

    考虑先固定左边的竖线,然后枚举从左到右枚举右边的竖线,那么随着右边竖线的右移,合法的横线(右端点大于等于某个值的横线)数量只会越来越少

    所以枚举右边竖线的时候同时动态维护一个指向当前最左的右端点合法的横线,然后动态维护树状数组就行了

    答案也很容易计算,在固定了左右竖线的情况下,设中间有 $p$ 个最小的不可分割的矩形,那么贡献即为 $p(p+1)/2$

    (枚举大矩形包含了 $k$ 小矩形,那么就是 $sum_{k=1}^{p}(p-k+1)$)

    然后因为坐标系有负数所以统一加上 $5001$ 即可

    复杂度 $n^2 log 10000$,很稳

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=10007;
    struct Line {//竖线
        int x,l,r;
        Line (int _x=0,int _l=0,int _r=0) { x=_x,l=_l,r=_r; }
        inline bool operator < (const Line &tmp) const {
            return x!=tmp.x ? x<tmp.x : l<tmp.l;
        }
    }D[N];
    struct Line2 {//横线
        int h,l,r;
        Line2 (int _h=0,int _l=0,int _r=0) { h=_h,l=_l,r=_r; }
    }H1[N],H2[N];
    inline bool cmp1(Line2 &A,Line2 &B) { return A.l!=B.l ? A.l<B.l : A.r<B.r; }//把横线按左端点排序
    inline bool cmp2(Line2 &A,Line2 &B) { return A.r!=B.r ? A.r<B.r : A.l<B.l; }//按右端点排序
    int n,m,md,mh;
    struct BIT {//树状数组
        int t[N];
        inline void init() { memset(t,0,sizeof(t)); }
        inline void add(int x,int v) { while(x<=m) t[x]+=v,x+=x&-x; }
        inline int ask(int x) { int res=0; while(x) res+=t[x],x-=x&-x; return res; }
    }T;
    ll Ans;
    int main()
    {
        n=read(); int a,b,c,d;
        for(int i=1;i<=n;i++)
        {
            a=read()+5001,b=read()+5001,c=read()+5001,d=read()+5001;
            m=max(m,max(b,d));
            if(a==c)
            {
                if(b>d) swap(b,d);
                D[++md]=Line(a,b,d);
            }
            else
            {
                if(a>c) swap(a,c);
                H1[++mh]=Line2(b,a,c); H2[mh]=H1[mh];
            }
        }
        sort(D+1,D+md+1); sort(H1+1,H1+mh+1,cmp1); sort(H2+1,H2+mh+1,cmp2);
        for(int i=1;i<=md;i++)//枚举左边的竖线
        {
            int l=1,r=1;//动态维护指针
            while(l<=mh&&H1[l].l<=D[i].x) T.add(H1[l].h,1),l++;
            while(r<=mh&&H2[r].r<D[i].x) T.add(H2[r].h,-1),r++;
            for(int j=i+1;j<=md;j++)
            {
                while(r<=mh&&H2[r].r<D[j].x)
                {
                    if(H2[r].l<=D[i].x) T.add(H2[r].h,-1);//注意要判断是之前加入过的横线
                    r++;
                }
                if(D[i].x==D[j].x) continue;//相等不合法
                int L=max(D[i].l,D[j].l),R=min(D[i].r,D[j].r);
                if(L>=R) continue;//相等不合法
                int p=T.ask(R)-T.ask(L-1)-1; if(p<=0) continue;//构不成矩形
                Ans+=1ll*p*(p+1)/2;//累计贡献
            }
            while(r<=mh)//记得清空树状数组
            {
                if(H2[r].l<=D[i].x) T.add(H2[r].h,-1);
                r++;
            }
        }
        printf("%lld
    ",Ans);
        return 0;
    }
  • 相关阅读:
    H5 + 3D + AR/VR 综述
    10中典型的软件开发模型
    总线宽度VS总线带宽
    最全程序设计流程、技术、工具、交付结果【软件全生命周期】
    一幅图读懂面向对象和面向过程程序设计的区别!
    C语言实现计算器,附源码,超简单!
    request.getRequestDispatcher()的两个方法forward()/include()!!!
    关于使用ResultSet ---结果集没有当前行
    JComboBox添加item的赋值类型问题!不一致的话会导致不能更改jcombobox的选择值
    关于String的两种赋值方式
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/11597951.html
Copyright © 2011-2022 走看看