线段树+扫描线
扫描线
扫描线问题主要利用了线段树。
因为矩形的并集比较难算,所以我们可以用∑(扫描线被截长度×所扫描的高度)来求和。而这样做发现可以用线段树来优化,具体优化方式如下:所扫描的高度比较好求,主要是扫描线被截长度需要优化。
我们可以设横边有一个a权值,如果该边是矩阵的下边则设为1,相反就设为-1,这样如果一段区间(如果该区间正好与横边对应的话至少会对应两个边)的没有被截(或者说已经扫过去,加入答案中去了)则此时该区间所对应的线段树的a权值和一定为0.
相反,如果该区间已经被扫描线扫进去且会更新答案的话,则a权值一定不为0。
然后枚举每一条边,在线段树中更新a值和被覆盖长度的值。
最后答案加上总区间被覆盖长度的值的和乘高度差。
#include <bits/stdc++.h>
#define int long long
#define ls l, mid, root << 1
#define rs mid + 1, r, root << 1 | 1
using namespace std;
int n, cnt, _x1, _x2, _y9, _y3, x[1001000], sum;
struct g {
int l, r, y, s;
bool operator < (g c) {
return y < c.y;
}
}data[1001000];
struct node {
int l, r, a, len;
}ans[4001000];
void build(int l, int r, int root) {
ans[root].l = l, ans[root].r = r;
ans[root].len = ans[root].a = 0;
if (l == r) return;
int mid = (l + r) >> 1;
build(ls);
build(rs);
return;
}
inline void pushup(int root)
{
if (ans[root].a)//如果当前已经被覆盖
ans[root].len = x[ans[root].r + 1] - x[ans[root].l];//那就完全被覆盖了,就直接加上就好。
else//没有被覆盖的就需要递归求解
ans[root].len = ans[root << 1].len + ans[root << 1 | 1].len;
}
void update(int ql, int qr, int root, int add)
{
int l = ans[root].l, r = ans[root].r;
if (x[l] >= qr || x[r + 1] <= ql) return;
if (ql <= x[l] && x[r + 1] <= qr)
{
ans[root].a += add;
pushup(root);//完成操作后记得要更新,查看是否被覆盖了
return;
}
update(ql, qr, root << 1, add);
update(ql, qr, root << 1 | 1, add);
pushup(root);
}
signed main()
{
scanf("%lld", &n);//初始化
for (int i = 1; i <= n; i++)
{
scanf("%lld%lld%lld%lld", &_x1, &_y9, &_x2, &_y3);
data[++cnt].l = _x1, data[cnt].r = _x2, data[cnt].s = 1, data[cnt].y = _y9;
x[cnt] = _x1;
data[++cnt].l = _x1, data[cnt].r = _x2, data[cnt].s = -1, data[cnt].y = _y3;
x[cnt] = _x2;
} //离散化
sort(data + 1, data + 1 + cnt);//离散化首先需要排序+去重
sort(x + 1, x + 1 + cnt);
int block = unique(x + 1, x + 1 + cnt) - (x + 1);
build(1, block - 1, 1); //block-1就可以包含所有的区间了。建树时的都是离散化之后的点
for (int i = 1; i < cnt; i++)
{
update(data[i].l, data[i].r, 1, data[i].s);//更新扫描线信息
sum += ans[1].len * (data[i + 1].y - data[i].y);//面积=底X高 ,更新面积,
}
printf("%lld", sum);
return 0;
}
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 后端思维之高并发处理方案
· 理解Rust引用及其生命周期标识(下)
· 从二进制到误差:逐行拆解C语言浮点运算中的4008175468544之谜
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· 2025成都.NET开发者Connect圆满结束
· 后端思维之高并发处理方案
· 千万级大表的优化技巧
· 在 VS Code 中,一键安装 MCP Server!
· 10年+ .NET Coder 心语 ── 继承的思维:从思维模式到架构设计的深度解析