CF E68 E. Count The Rectangles//树状数组统计线段组成矩形个数

题目

题意

给n条线段,要么水平要么垂直,都不相交(除了水平和垂直的)。求能组成的矩形个数。

思路

md思路错了,这题给我整自闭了
暴力枚举复杂度 O ( n 4 ) O(n^4) O(n4)
考虑固定两条水平的,枚举垂直的,假设有 x x x条能垂直切割那两条水平的线段,那么这两条水平的对答案的贡献就是 C ( n , 2 ) C(n,2) C(n,2),这样复杂度 O ( n 3 ) O(n^3) O(n3)
继续优化:
考虑枚举一条水平的线段 l [ i ] l[i] l[i],将与它垂直的并且相交的线段的切割点的横坐标加入BIT,从 l [ i ] . x l[i].x l[i].x往上扫,考虑矩形的上边与BIT里的线段的交点,并计算贡献。当然向上扫的过程中也要不停的把BIT里的线段删去(当垂直的线段不能再有贡献的时候)。

/*   Author : Rshs
 *   Data : 2019-09-25-19.22
 */
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const double pai = acos(-1);
const double eps = 1e-10;
const LL mod = 1e9+7;
const int MX = 1e4+20;
/*************************************************************/
LL bit[MX];
void up(int p,LL x,int nn){
    while(p<=nn) bit[p]+=x,p=p+(p&-p);
}
LL qu(int p){
    LL re=0;
    while(p>0) re+=bit[p],p=p-(p&-p);
    return re;
}
/*************************************************************/
struct LINE {
    int a,b,x,y;
}line[MX];
bool cmp(LINE u,LINE v){
    return u.y<v.y;
}
vector<LINE>v,hh;
vector<LINE>h[MX];
vector<int>bj[MX];
int main(){
    LL n;cin>>n;
    for(int i=1;i<=n;i++){          //1,10001
        int sa,sb,sc,sd;cin>>sa>>sb>>sc>>sd;
        line[i].a=min(sa,sc)+5001,line[i].x=max(sa,sc)+5001;
        line[i].b=min(sb,sd)+5001,line[i].y=max(sb,sd)+5001;
        if(line[i].x==line[i].a) v.push_back(line[i]);
        else h[line[i].y].push_back(line[i]),hh.push_back(line[i]);
    }
    LL ans=0;
    for(auto i:hh){
        memset(bit,0,sizeof(bit));
        for(int i=0;i<=1e4+2;i++) bj[i].clear();
        int ta=i.a,tx=i.x,ty=i.y;
        for(auto j:v){
            if(j.x>tx||j.x<ta||j.y<ty||j.b>ty) continue;//无相交
            bj[j.y+1].push_back(j.x);//消除的标记
            up(j.x,1,1e4+5);
        }
        for(int j=i.y+1;j<=1e4+1;j++){
            for(auto k:bj[j]) up(k,-1,1e4+5);//标记处理
            for(auto now:h[j]){
                LL gg=qu(now.x)-qu(now.a-1);
                ans=ans+gg*(gg-1)/2;
            }
        }
    }
    cout<<ans;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值