Codeforces 1401E. Divide Square (扫描线 + 线段树)

Description
There is a square of size 106×106 on the coordinate plane with four points (0,0), (0,106), (106,0), and (106,106) as its vertices.

You are going to draw segments on the plane. All segments are either horizontal or vertical and intersect with at least one side of the square.

Now you are wondering how many pieces this square divides into after drawing all segments. Write a program calculating the number of pieces of the square.

Input
The first line contains two integers n and m (0≤n,m≤105) — the number of horizontal segments and the number of vertical segments.

The next n lines contain descriptions of the horizontal segments. The i-th line contains three integers yi, lxi and rxi (0<yi<106; 0≤lxi<rxi≤106), which means the segment connects (lxi,yi) and (rxi,yi).

The next m lines contain descriptions of the vertical segments. The i-th line contains three integers xi, lyi and ryi (0<xi<106; 0≤lyi<ryi≤106), which means the segment connects (xi,lyi) and (xi,ryi).

It’s guaranteed that there are no two segments on the same line, and each segment intersects with at least one of square’s sides.

Output
Print the number of pieces the square is divided into after drawing all the segments.

Example
Input
3 3
2 3 1000000
4 0 4
3 0 1000000
4 0 1
2 0 5
3 1 1000000
Output
7

Solution
答案 = 1 + 任意两线段的交点数(不包括边界) + 连接了相对的俩边界的线段数

问题转化为如何求任意两线段的交点数

以平行于Y轴的扫描线扫描:
若遇到平行线段左端点,则在对应的Y轴上添加该线段
若遇到平行线段右端点,则在对应的Y轴上删除该线段
若遇到垂直线段,则区间查询对应的Y轴区间上存在多少覆盖点,并累加到答案

Hint
坐标范围足够小,不需要离散化
以Y坐标建立线段树,需要将坐标+1来避免0点造成影响

Code

#define pb push_back
#define ls rt << 1
#define rs rt << 1 | 1
#define pii pair<int,int>
#define mpp make_pair
#define fi first
#define se second
const int maxn = 1e6 + 7;
vector<pii>Y[maxn];
vector<int>X1[maxn],X2[maxn];
struct Segtree{
    int l,r;
    int sum;
}t[maxn<<2];
inline void push_up(int rt) {
    t[rt].sum = t[ls].sum + t[rs].sum;
}

void build(int rt,int l,int r) {
    t[rt].l = l, t[rt].r = r;
    if(l == r) {
        t[rt].sum = 0; return ;
    }
    int mid = (l + r) >> 1;
    build(ls,l,mid);build(rs,mid+1,r);
    push_up(rt);
}

void add(int rt,int pos,int v) {
    int l = t[rt].l, r = t[rt].r;
    if(l == r) {
        t[rt].sum += v;return ;
    }
    int mid = (l + r) >> 1;
    if(pos <= mid) add(ls,pos,v);
    else add(rs,pos,v);
    push_up(rt);
}

int ask(int rt,int L,int R) {
    int l = t[rt].l, r = t[rt].r;
    if(L <= l && r <= R) {
        return t[rt].sum;
    }
    int mid = (l + r) >> 1, res = 0;
    if(L <= mid) res += ask(ls,L,R);
    if(R  > mid) res += ask(rs,L,R);
    return res;
}
int lim = 1e6;
int main() {
    ll res = 1;
    int n,m;scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;++i) {
        int y,x1,x2;scanf("%d%d%d",&y,&x1,&x2);
        X1[x1].pb(y);X2[x2].pb(y);
        if(x1 == 0 && x2 == lim) res++;
    }
    for(int i = 1;i <= m;++i) {
        int x,y1,y2;scanf("%d%d%d",&x,&y1,&y2);
        Y[x].pb({y1,y2});
        if(y1 == 0 && y2 == lim) res++;
    }
    build(1,1,lim+1);
    for(int i = 0;i <= lim;++i) {
        for(auto y : X1[i]) {
            add(1,y+1,1);
        }
        for(auto q : Y[i]) {
            res += ask(1,q.fi+1,q.se+1);
        }
        for(auto y : X2[i]) {
            add(1,y+1,-1);
        }
    }
    printf("%lld\n", res);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值