题目链接: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; }