[ABC211F] Rectilinear Polygons 题解
1.AT_abc333_e [ABC333E] Takahashi Quest 题解2.[ABC265F] Manhattan Cafe 题解3.[ABC271E] Subsequence Path 题解4.[ABC273D] LRUD Instructions 题解5.P8085 [COCI2011-2012#4] KRIPTOGRAM 题解6.[ABC238F] Two Exams 题解7.[ABC217F] Make Pair 题解8.[ABC219F] Cleaning Robot 题解9.[ABC219E] Moat 题解10.[ABC221D] Online games 题解11.[ABC221E] LEQ 题解12.[ABC223E] Placing Rectangles 题解13.[ABC211D] Number of Shortest paths 题解
14.[ABC211F] Rectilinear Polygons 题解
15.[ABC223F] Parenthesis Checking 题解16.CF154C Double Profiles 题解17.[ABC208D] Shortest Path Queries 2 题解18.[ABC212E] Safety Journey 题解19.[ABC229E] Graph Destruction 题解20.[ABC240E] Ranges on Tree 题解21.[ABC261E] Many Operations 题解22.P10842 【MX-J2-T3】Piggy and Trees 题解[ABC211F] Rectilinear Polygons 题解
思路什么的上一篇题解已经写的非常明白了,这里只是提供一个补充 & 另一个实现的方法。
思路解析
先说结论:扫描线。顾名思义,扫描线的本质就是用一条线沿着
这里就不过多解释,如果没有学过扫描线建议去做一下模板题,推荐看第一篇题解。
接下来就是本题的重点,该如何把不规则图形存下来。如下图,我们先把图上的竖边找出来,同时给点的顺序标一个号。
可见四条边中左边三条的权值都是增加的,只有右边一条是减少的。我们寻找边上的两点和权值的关系,可以发现,由于是点顺序输入的,所以每一条正边权的边的两点中编号较小的点
实现
我们根据以上所说的方式存好每一条边,然后将边按
接下来有几点注意事项。
- 题目中的输入点的顺序不一定满足我们想要的输入顺序,所以我们需要自己找到一个在
最小的情况下 也最小的点做编号为 的点。 - 由于我们只需要知道一个点被覆盖的次数,所以可以将模板中的线段树换成树状数组区修单查。
- 由于我们需要先把当前
轴上的边加完再统计询问,所以我们要在所有边的最后加上一个 的边,这样就能防止最后有几个点没有处理到。
code
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, M = 1e5;
int n, m, xx[N], yy[N], tv[N], q, c[N], ans[N];
struct side {
int x, ya, yb, val;
};
struct point {
int x, ya, yb;
};
struct query {
int x, y, p;
};
void add(int x, int y) {
for(; x <= M; x += (x & -x)) {
c[x] += y;
}
}
int ask(int x) {
int sum = 0;
for(; x > 0; x -= (x & -x)) {
sum += c[x];
}
return sum;
}
int main() {
cin >> n;
vector<side> v;
for(int i = 1; i <= n; i++) {
cin >> m;
for(int i = 0; i < m; i++) {
cin >> xx[i] >> yy[i];
xx[i]++; yy[i]++;
}
int p = 0;
for(int i = 0; i < m; i++) {
if(xx[i] == xx[p] && yy[i] < yy[p]) p = i; //找到起始点,注意 y 轴也要判
else if(xx[i] < xx[p]) p = i;
}
int val = 1;
for(int i = 0; i < m; i++) {
int w = (i + p) % m;
tv[w] = val; //给点加权
val = -val;
}
for(int i = 0; i < m; i += 2) { //判断
if(yy[i] < yy[i + 1]) v.push_back({xx[i], yy[i], yy[i + 1], tv[i]});
else v.push_back({xx[i], yy[i + 1], yy[i], tv[i + 1]});
}
}
sort(v.begin(), v.end(), [](side x, side y) { //按 x 排序
if(x.x != y.x) return x.x < y.x;
else return x.ya < y.ya;
});
v.push_back({M + 1, 1, 1, 0}); //避免结尾有点没判
vector<query> que;
cin >> q;
for(int i = 1; i <= q; i++) {
cin >> xx[i] >> yy[i];
xx[i]++; yy[i]++;
que.push_back({xx[i], yy[i], i}); //离线
}
sort(que.begin(), que.end(), [](query x, query y) { //排序
if(x.x != y.x) return x.x < y.x;
else return x.y < y.y;
});
int pos = 0;
for(auto it : v) {
int x = it.x, ya = it.ya, yb = it.yb, val = it.val;
for(; que[pos].x < x && pos < (int)que.size(); pos++) {
ans[que[pos].p] = ask(que[pos].y); //若已经操作完则更新
}
add(ya, val); add(yb, -val); //加权
}
for(int i = 1; i <= q; i++) cout << ans[i] << '\n';
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通