4e5大小的线段树来喽!怎么,都RE了? Luogu P3875 [TJOI2010]被污染的河流

P3875 [TJOI2010]被污染的河流 题解

本来是为了改昨天的题,发现扫描线基本上都忘了,打算找个扫描线练练手,结果打的有来有回的。

解析

污染区域是以河流为中线的一块矩形,可能生病的社区数量就是这些矩形的面积并。

很显然是扫描线,线段树维护。

存储每个矩形左,右边界,左边界赋1,右边界赋-1 ,把线段排序,再依次处理每一条线段。

整体来说挺板子的,需要注意一些小细节。

河流起始位置和结束位置的坐标不一定先左后右,先下后上,所以要swap一下。

x值相等时,河流为纵向流向,左边界的x值为 x - 1,右边界的x值为 x + 1。

y值相等时,河流为横向流向,左,右边界的yl(下方的端点)值为 y - 1,yl(上方的端点)值为 y + 1。

因为有 - 1 和 + 1 的操作,所以端点会出现值为 0 或 1000001 的情况,线段树初始化的时候要注意。

最重要的是,4e5 大小的线段树会RE,所以开大一点。

Code

#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 1e4 + 10, MAXM = 2e5 + 10;
int n, sum, maxr;
struct Line{
int x;
int yh, yl;
int sit;
}line[MAXM << 1];
inline bool cmp(const Line &a, const Line &b){
return a.x < b.x;
}
struct Segment_Tree{
struct Tree{
int l, r;
int len;
int cnt;
}tr[MAXM << 2];
inline int lson(int rt){
return rt << 1;
}
inline int rson(int rt){
return rt << 1 | 1;
}
inline void Pushup(int rt){
if(tr[rt].cnt)
tr[rt].len = tr[rt].r - tr[rt].l + 1;
else
tr[rt].len = tr[lson(rt)].len + tr[rson(rt)].len;
}
void Build(int rt, int l, int r){
tr[rt].l = l;
tr[rt].r = r;
tr[rt].len = 0;
tr[rt].cnt = 0;
if(l == r)
return;
int mid = (l + r) >> 1;
Build(lson(rt), l, mid);
Build(rson(rt), mid + 1, r);
}
void Update(int rt, int l, int r, int data){
if(tr[rt].l >= l && tr[rt].r <= r){
tr[rt].cnt += data;
Pushup(rt);
return;
}
int mid = (tr[rt].l + tr[rt].r) >> 1;
if(l <= mid) Update(lson(rt), l, r, data);
if(r > mid) Update(rson(rt), l, r, data);
Pushup(rt);
}
}S;
inline int read(){
int x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9'){
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9'){
x = (x << 1) + (x << 3) + (c ^ 48);
c = getchar();
}
return x * f;
}
int main(){
n = read();
for(register int i = 1; i <= n; i++){
int x1, y1, x2, y2;
x1 = read(), y1 = read(), x2 = read(), y2 = read();
if(x1 > x2) swap(x1, x2);
if(y1 > y2) swap(y1, y2);
if(x1 == x2){
line[(i << 1) - 1].x = x1 - 1, line[(i << 1)].x = x2 + 1;
line[(i << 1) - 1].yl = line[(i << 1)].yl = y1;
line[(i << 1) - 1].yh = line[(i << 1)].yh = y2;
line[(i << 1) - 1].sit = 1;
line[(i << 1)].sit = -1;
}
else if(y1 == y2){
line[(i << 1) - 1].x = x1, line[(i << 1)].x = x2;
line[(i << 1) - 1].yl = line[(i << 1)].yl = y1 - 1;
line[(i << 1) - 1].yh = line[(i << 1)].yh = y2 + 1;
line[(i << 1) - 1].sit = 1;
line[(i << 1)].sit = -1;
}
}
n <<= 1;
sort(line + 1, line + 1 + n, cmp);
S.Build(1, 0, 100001);
for(register int i = 1; i < n; i++){
S.Update(1, line[i].yl, line[i].yh - 1, line[i].sit);
sum += S.tr[1].len * (line[i + 1].x - line[i].x);
}
printf("%d\n", sum);
return 0;
}
posted @   TSTYFST  阅读(35)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示