寒假Day48:HDU1542-Atlantis-矩形面积和-线段树+扫描线
题目链接:HDU - 1542
样例:
Sample Input 2 10 10 20 20 15 15 25 25.5 0 Sample Output Test case #1 Total explored area: 180.00
题意:给出一个n,n≠0,给出n行数据,每一行给出一个矩形的左下角和右上角坐标(x1,y1,x2,y2)
每组数据输出n个矩形在坐标图上面的覆盖面积
思路:线段树扫描线模板题
注意:
line数组需要开两倍,因为每个矩形给出的是两个坐标。
线段树扫描线中的tree数组需要开8倍,一般线段树开4倍。
需要用到的数组和结构体:
const int N=110; double y[N<<1];//记录y坐标 struct node { int l,r,c;//线段树左右点、cover重叠覆盖情况 double len,lf,rf;//实际情况 } tree[N<<3]; struct Line { int f;//矩形:入边 左1 ,出边 右 -1 double x,up,down;//线段的横坐标、上下纵坐标 } line[N<<1];
建树操作:
void build(int i,int L,int R) { tree[i].l=L,tree[i].r=R; tree[i].c=tree[i].len=0; tree[i].lf=y[L],tree[i].rf=y[R]; if(L+1==R) return ; int mid=(L+R)>>1; build(i<<1,L,mid); build(i<<1|1,mid,R);//不是mid+1,是[1,2][2,3],不是[1,2][3,4] }
pushup操作:
void pushup(int i)//更新以下信息去维护整棵树 { if(tree[i].c) { tree[i].len=tree[i].rf-tree[i].lf; return; } //下面都是tree[i].c==0的,说明没有被覆盖 if(tree[i].l+1==tree[i].r)//是叶子节点, tree[i].len=0; else//是一条整个区间没有被全部覆盖的线段 tree[i].len=tree[i<<1].len+tree[i<<1|1].len; }
update操作:
void update(int i,Line a)//加入一条新线段、更新线段树 { if(a.down==tree[i].lf&&a.up==tree[i].rf) { tree[i].c+=a.f; pushup(i); return; } if(a.up<=tree[i<<1].rf) update(i<<1,a); else if(a.down>=tree[i<<1|1].lf) update(i<<1|1,a); else { Line b=a,c=a; b.up=tree[i<<1].rf,c.down=tree[i<<1|1].lf; update(i<<1,b); update(i<<1|1,c); } pushup(i); }
AC代码:
#include<stdio.h> #include<iostream> #include<string.h> #include<algorithm> #include<queue> using namespace std; #define inf 0x3f3f3f3f typedef long long ll; const int N=110; double y[N<<1];//记录y坐标 struct node { int l,r,c;//线段树左右点、cover重叠覆盖情况 double len,lf,rf;//实际情况 } tree[N<<3]; struct Line { int f;//矩形:入边 左1 ,出边 右 -1 double x,up,down;//线段的横坐标、上下纵坐标 } line[N<<1]; bool cmp1(Line x,Line y) { return x.x<y.x; } void build(int i,int L,int R) { tree[i].l=L,tree[i].r=R; tree[i].c=tree[i].len=0; tree[i].lf=y[L],tree[i].rf=y[R]; if(L+1==R) return ; int mid=(L+R)>>1; build(i<<1,L,mid); build(i<<1|1,mid,R);//不是mid+1,是[1,2][2,3],不是[1,2][3,4] } void pushup(int i)//更新以下信息去维护整棵树 { if(tree[i].c) { tree[i].len=tree[i].rf-tree[i].lf; return; } //下面都是tree[i].c==0的,说明没有被覆盖 if(tree[i].l+1==tree[i].r)//是叶子节点, tree[i].len=0; else//是一条整个区间没有被全部覆盖的线段 tree[i].len=tree[i<<1].len+tree[i<<1|1].len; } void update(int i,Line a)//加入一条新线段、更新线段树 { if(a.down==tree[i].lf&&a.up==tree[i].rf) { tree[i].c+=a.f; pushup(i); return; } if(a.up<=tree[i<<1].rf) update(i<<1,a); else if(a.down>=tree[i<<1|1].lf) update(i<<1|1,a); else { Line b=a,c=a; b.up=tree[i<<1].rf,c.down=tree[i<<1|1].lf; update(i<<1,b); update(i<<1|1,c); } pushup(i); } int main() { int n,tt=1; while(~scanf("%d",&n)&&n) { int k=1; for(int i=1; i<=n; i++) { double x1,y1,x2,y2; scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2); line[k].x=x1,line[k].down=y1,line[k].up=y2,line[k].f=1; y[k++]=y1; line[k].x=x2,line[k].down=y1,line[k].up=y2,line[k].f=-1; y[k++]=y2; } sort(line+1,line+k,cmp1); sort(y+1,y+k); build(1,1,k-1); update(1,line[1]); double ans=0; for(int i=2; i<k; i++)//扫描线段 { ans+=tree[1].len*(line[i].x-line[i-1].x);//增加新的面积 update(1,line[i]); } printf("Test case #%d\n",tt++); printf("Total explored area: %.2f\n\n",ans);//两个\n } return 0; }
分类:
线段树/树状数组
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」