扫描线模板(矩形面积并与周长并)
扫描线模板(矩形面积并)
首先离散化的思想,将各个线段细分到单位长,于是就是动态求当前值域内 tag
以下是参考代码,十分优美
int n, cnt;
ll xx[N];
struct Scanline{
ll y;
ll lx, rx;
int inout;
bool operator < (const Scanline &t) const{
return y < t.y;
}
}line[N];
void lineadd(ll yt, ll lxt, ll rxt, int inoutt, int count){
line[count].inout = inoutt;
line[count].y = yt;
line[count].lx = lxt;
line[count].rx = rxt;
}
int ls(int p){return p << 1;}
int rs(int p){return p << 1|1;}
struct SegmentTree{
ll tree[N << 2|1];
int tag[N << 2 |1];
inline void push_up(int p, int pl, int pr){
// 向上传递节点,更新节点值
if(tag[p]){
tree[p] = xx[pr] - xx[pl];
}else if(pl + 1 == pr){
tree[p] = 0;
}else{
tree[p] = tree[ls(p)] + tree[rs(p)];
}
}
inline void update(int L, int R, int p, int pl, int pr, int inoutt){
if(L <= pl && pr <= R){
tag[p] += inoutt;
push_up(p, pl, pr);
return ;
}
if(pl + 1 == pr) return ;
int mid = (pl + pr) >> 1;
if(L <= mid){
update(L, R, ls(p), pl, mid, inoutt);
}
if(R >= mid + 1){
update(L, R, rs(p), mid, pr, inoutt); // 注意不是 mid + 1,因为连续性
}
push_up(p, pl, pr);
}
};
SegmentTree seg;
void solve() {
cin >> n;
ll x1, x2, y1, y2;
for(int i = 1; i <= n; i++){
cin >> x1 >> y1 >> x2 >> y2;
lineadd(y1, x1, x2, 1, ++cnt);
xx[cnt] = x1;
lineadd(y2, x1, x2, -1, ++cnt);
xx[cnt] = x2;
}
sort(xx + 1, xx + 1 + cnt);
sort(line + 1, line + 1 + cnt);
int xlen = unique(xx + 1, xx + 1 + cnt) - (xx + 1);
ll ans = 0;
for(int i = 1; i <= cnt; i++){
ans += seg.tree[1]*(line[i].y - line[i - 1].y);
int L = lower_bound(xx + 1, xx + 1 + xlen, line[i].lx) - xx;
int R = lower_bound(xx + 1, xx + 1 + xlen, line[i].rx) - xx;
seg.update(L, R, 1, 1, xlen, line[i].inout);
}
cout << ans << "\n";
}
矩形周长并复杂一些,并且存在一个细节 - 对于高度相同线的先增后删,避免两条边重合
思路是分成竖边和横边,分别计算,每条边的对答案的贡献是这一条边加上后的变化值(tag &>0& 的数量)
以下是参考代码:
// Created by qyy on 2024/10/6.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define PII pair<int, int>
#define endl "\n"
const long long inf = 0x3f3f3f3f3f3f3f3f;
const int N = 2e5 + 10;
const int mod = 7;
int n, cnt, cnt2;
ll xx[N], xx2[N];
struct Scanline{
ll y;
ll lx, rx;
int inout;
}line[N], line2[N];
bool cmp(Scanline a, Scanline b){
if(a.y != b.y){
return a.y < b.y;
}else{
return a.inout > b.inout;
}
}
void lineadd(ll yt, ll lxt, ll rxt, int inoutt, int count){
line[count].inout = inoutt;
line[count].y = yt;
line[count].lx = lxt;
line[count].rx = rxt;
}
void lineadd2(ll yt, ll lxt, ll rxt, int inoutt, int count){
line2[count].inout = inoutt;
line2[count].y = yt;
line2[count].lx = lxt;
line2[count].rx = rxt;
}
int ls(int p){return p << 1;}
int rs(int p){return p << 1|1;}
struct SegmentTree{
ll tree[N << 2|1];
int tag[N << 2 |1];
inline void push_up(int p, int pl, int pr){
// 向上传递节点,更新节点值
if(tag[p]){
tree[p] = xx[pr] - xx[pl];
}else if(pl + 1 == pr){
tree[p] = 0;
}else{
tree[p] = tree[ls(p)] + tree[rs(p)];
}
}
inline void update(int L, int R, int p, int pl, int pr, int inoutt){
if(L <= pl && pr <= R){
tag[p] += inoutt;
push_up(p, pl, pr);
return ;
}
if(pl + 1 == pr) return ;
int mid = (pl + pr) >> 1;
if(L <= mid){
update(L, R, ls(p), pl, mid, inoutt);
}
if(R >= mid + 1){
update(L, R, rs(p), mid, pr, inoutt); // 注意不是 mid + 1,因为连续性
}
push_up(p, pl, pr);
}
};
SegmentTree seg;
void solve() {
cin >> n;
ll x1, x2, y1, y2;
for(int i = 1; i <= n; i++){
cin >> x1 >> y1 >> x2 >> y2;
lineadd(y1, x1, x2, 1, ++cnt);
xx[cnt] = x1;
lineadd(y2, x1, x2, -1, ++cnt);
xx[cnt] = x2;
lineadd2(x1, y1, y2, 1, ++cnt2);
xx2[cnt2] = y1;
lineadd2(x2, y1, y2, -1, ++cnt2);
xx2[cnt2] = y2;
}
sort(xx + 1, xx + 1 + cnt);
sort(line + 1, line + 1 + cnt, cmp);
int xlen = unique(xx + 1, xx + 1 + cnt) - (xx + 1);
ll ans = 0;
ll last = 0;
for(int i = 1; i <= cnt; i++){
int L = lower_bound(xx + 1, xx + 1 + xlen, line[i].lx) - xx;
int R = lower_bound(xx + 1, xx + 1 + xlen, line[i].rx) - xx;
last = seg.tree[1];
seg.update(L, R, 1, 1, xlen, line[i].inout);
ans += abs(seg.tree[1] - last);
}
for(int i = 1; i <= cnt; i++){
line[i] = line2[i];
xx[i] = xx2[i];
}
memset(seg.tree, 0, sizeof(seg.tree));
memset(seg.tag, 0, sizeof(seg.tag));
sort(xx + 1, xx + 1 + cnt);
sort(line + 1, line + 1 + cnt, cmp);
xlen = unique(xx + 1, xx + 1 + cnt) - (xx + 1);
for(int i = 1; i <= cnt; i++){
int L = lower_bound(xx + 1, xx + 1 + xlen, line[i].lx) - xx;
int R = lower_bound(xx + 1, xx + 1 + xlen, line[i].rx) - xx;
last = seg.tree[1];
seg.update(L, R, 1, 1, xlen, line[i].inout);
ans += abs(seg.tree[1] - last);
}
cout << ans << "\n";
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
//cin >> t;
while (t--) {
solve();
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)