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

The next m lines contain descriptions of the vertical segments. The i-th line contains three integers xi, lyi and ryi (0

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
#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;
}

你可能感兴趣的:(扫描线,线段树,Codeforces)