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;
    }
  • 相关阅读:
    Mac OSX下增加TCP连接数
    Connection reset by peer的常见原因及解决办法
    修改主机名
    docker 查看 docker容器启动 完整命令
    nginx 日志打印响应时间 request_time 和 upstream_response_time
    Ubuntu16.04 安装 Docker
    VictoriaMetrics vmagent 使用
    VictoriaMetrics vmauth 使用
    VictoriaMetrics集群模式的一些说明
    promgen prometheus 配置文件生成工具
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/11597951.html
Copyright © 2011-2022 走看看