首页 > 其他分享 >acwing 1228. 油漆面积 扫描线

acwing 1228. 油漆面积 扫描线

时间:2022-08-13 18:40:21浏览次数:72  
标签:矩形 tr len 1228 x2 扫描线 y1 y2 acwing

 

X星球的一批考古机器人正在一片废墟上考古。

该区域的地面坚硬如石、平整如镜。

管理人员为方便,建立了标准的直角坐标系。

每个机器人都各有特长、身怀绝技。

它们感兴趣的内容也不相同。

经过各种测量,每个机器人都会报告一个或多个矩形区域,作为优先考古的区域。

矩形的表示格式为 (x1,y1,x2,y2)(x1,y1,x2,y2),代表矩形的两个对角点坐标。

为了醒目,总部要求对所有机器人选中的矩形区域涂黄色油漆。

小明并不需要当油漆工,只是他需要计算一下,一共要耗费多少油漆。

其实这也不难,只要算出所有矩形覆盖的区域一共有多大面积就可以了。

注意,各个矩形间可能重叠。

输入格式

第一行,一个整数 nn,表示有多少个矩形。

接下来的 nn 行,每行有 44 个整数 x1,y1,x2,y2x1,y1,x2,y2,空格分开,表示矩形的两个对角顶点坐标。

输出格式

一行一个整数,表示矩形覆盖的总面积。

数据范围

1≤n≤100001≤n≤10000,
0≤x1,x2,y2,y2≤100000≤x1,x2,y2,y2≤10000
数据保证 x1<x2x1<x2 且 y1<y2y1<y2。

输入样例1:

3
1 5 10 10
3 1 20 20
2 7 15 17

输出样例1:

340

输入样例2:

3
5 2 10 6
2 7 12 10
8 1 15 15

输出样例2:

128

分析

从左往右遍历所有的线段,如果遇到左端点,就在线段数里加上这条线,遇到右端点,就在线段树里减去这条线。

线段树的len 表示当前区间被覆盖的长度,cnt表示当前区间被多少条线整体覆盖。

类似于差分求当前点被多少条线覆盖,遇到一个矩形左边的线 cnt + 1,遇到右边的线 cnt - 1。当前线如果被覆盖,当前区间的len 就是r - l + 1。如果当前线没有被覆盖,当前区间的长度是从子节点传上来的。

删除一条线的时候,当前区间的len 会直接变成0吗?不会,因为除了本身有长度,子区间也有长度。长度是从子区间传上来的长度。

 

//-------------------------代码----------------------------

//#define int ll
const int N = 1e5+10;
int n,m;

struct segment { 
    int x,y1,y2,k;
    bool operator<(segment X) {
        return x < X.x;
    }
} seg[N * 2];
struct node {
    int l,r,cnt,len;
} tr[N<<2];

void build(int u, int l, int r)
{
    tr[u] = {l, r};
    if (l == r) return;
    int mid = l + r >> 1;
    build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
}
void push_up(int u)
{
    if (tr[u].cnt > 0) tr[u].len = tr[u].r - tr[u].l + 1;
    else if (tr[u].l == tr[u].r) tr[u].len = 0;
    else tr[u].len = tr[u << 1].len + tr[u << 1 | 1].len;
}

void modify(int u, int l, int r, int k)
{
    if (tr[u].l >= l && tr[u].r <= r)
    {
        tr[u].cnt += k;
        push_up(u);
    }
    else
    {
        int mid = tr[u].l + tr[u].r >> 1;
        if (l <= mid) modify(u << 1, l, r, k);
        if (r > mid) modify(u << 1 | 1, l, r, k);
        push_up(u);
    }
}

void solve()
{
    scanf("%d", &n);
    int m = 0;
    for (int i = 0; i < n; i ++ )
    {
        int x1, y1, x2, y2;
        scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        seg[m ++ ] = {x1, y1, y2, 1};
        seg[m ++ ] = {x2, y1, y2, -1};
    }

    sort(seg, seg + m);

    build(1, 0, 10000);

    int res = 0;
    for (int i = 0; i < m; i ++ )
    {
        if (i > 0) res += tr[1].len * (seg[i].x - seg[i - 1].x);
        modify(1, seg[i].y1, seg[i].y2 - 1, seg[i].k);
    }

    printf("%d\n", res);

}
void main_init() {}
signed main(){
    TLE;
    cout<<fixed<<setprecision(12);
    main_init();
//  while(cin>>n,n)
//  while(cin>>n>>m,n,m)
//    int t;cin>>t;while(t -- )
    solve();
//    {solve(); }
    return 0;
}

/*样例区


*/

//------------------------------------------------------------

 

标签:矩形,tr,len,1228,x2,扫描线,y1,y2,acwing
From: https://www.cnblogs.com/er007/p/16583762.html

相关文章