CodeForces1401 E.Divide Square(扫描线,线段树)

题意:

有一个1e6*1e6的二维坐标平面,
左下角为(0,0),右上角为(1e6,1e6),
给定n条横线段,和m条竖线段,
问将平面分割成多少块区域。

数据范围:n,m<=1e5,保证线段的两端点至少有一个在正方形的边上。
在这里插入图片描述

解法:
如果不存在一条线段直接将正方形切切割成两份的情况,那么答案就是交点数量+1
如果存在直接切割的情况,每有一条答案+1,这个特判一下就行了.

关键在于如何求交点数量:
用线段树扫描线的思想,将线段拆分为修改和询问.
用竖着的扫描线从x=0向右扫:
1.遇到横线的左端点就加入线段树,
2.遇到横线的右端点就消除,
3.遇到竖线就统计线段树中有多少个点和这个竖线相交
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=1e6+5;
int a[maxm<<2];
int b[maxm<<2],num;
int n,m;
struct Node{
    int x,y1,y2,op;
    bool operator<(const Node& a)const{
        if(x!=a.x)return x<a.x;
        return op<a.op;
    }
}e[maxm<<2];
void pushup(int node){
    a[node]=a[node*2]+a[node*2+1];
}
void update(int x,int val,int l,int r,int node){
    if(l==r){
        a[node]+=val;
        return ;
    }
    int mid=(l+r)/2;
    if(x<=mid)update(x,val,l,mid,node*2);
    else update(x,val,mid+1,r,node*2+1);
    pushup(node);
}
int ask(int st,int ed,int l,int r,int node){
    if(st<=l&&ed>=r)return a[node];
    int mid=(l+r)/2;
    int ans=0;
    if(st<=mid)ans+=ask(st,ed,l,mid,node*2);
    if(ed>mid)ans+=ask(st,ed,mid+1,r,node*2+1);
    return ans;
}
signed main(){
    ios::sync_with_stdio(0);
    const int p=1e6;
    cin>>n>>m;
    int tot=0;
    int ans=1;
    for(int i=1;i<=n;i++){
        int y,l,r;cin>>y>>l>>r;
        if(l==0&&r==p)ans++;
        b[++num]=y;
        e[++tot]={l,y,-1,1};
        e[++tot]={r+1,y,-1,2};
    }
    for(int i=1;i<=m;i++){
        int x,l,r;cin>>x>>l>>r;
        if(l==0&&r==p)ans++;
        b[++num]=l;
        b[++num]=r;
        e[++tot]={x,l,r,3};
    }
    sort(e+1,e+1+tot);
    b[++num]=0,b[++num]=1e6;
    sort(b+1,b+1+num);
    num=unique(b+1,b+1+num)-b-1;
    for(int i=1;i<=tot;i++){
        if(e[i].op==1){
            int x=lower_bound(b+1,b+1+num,e[i].y1)-b;
            update(x,1,1,p,1);
        }else if(e[i].op==2){
            int x=lower_bound(b+1,b+1+num,e[i].y1)-b;
            update(x,-1,1,p,1);
        }else if(e[i].op==3){
            int l=lower_bound(b+1,b+1+num,e[i].y1)-b;
            int r=lower_bound(b+1,b+1+num,e[i].y2)-b;
            ans+=ask(l,r,1,p,1);
        }
    }
    cout<<ans<<endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值