标签:corn 排列 back nio test res ble should val
2 10 10 20 20 15 15 25 25.5 0Sample Output
Test case #1 Total explored area: 180.00
题意:给出n个矩形,和它们的左下角和右上角的坐标,求所有矩形的覆盖面积
分析:扫描线的经典题,用线段树维护当前状态覆盖的横坐标的区间总和,这样到下一条扫描线为止的高度和它的乘积,一定是被覆盖的面积。
由于题目的坐标是浮点数,所以首先需要进行离散化处理,对应到整型数上
然后用[l,r]代表l到r+1的区间,因为要让线段树的每个节点都覆盖一个区间,所以[l,l]代表[l,l+1]的区间
线段树节点还需要维护区间的flag值,将矩形的横向边,分为入边和出边,当遇到入边时,flag++,遇到出边时flag--,当flag>0时,就代表当前节点的区间被覆盖
这样树的根节点的权值,就代表总的被覆盖区间的和,再乘以扫描线高度的差,即为当前状态下被覆盖的面积,进行累加即可
关于扫描线,这篇博客讲的很详细:https://blog.csdn.net/u013480600/article/details/22548393
代码如下:
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <vector> using namespace std; const int MAXN=1010; typedef long long ll; vector<double>V; int get_id(double x) //将浮点数进行离散化处理 { return lower_bound(V.begin(),V.end(),x)-V.begin(); } struct node2 { double l,r; double h; int flag; }line[MAXN]; double sum[MAXN<<2];//储存该节点区间的被覆盖的长度 double tot[MAXN<<2];//储存该节点区间的总的长度 struct node { int l; int r; int f; }tree[MAXN<<2]; void PushUp(int rt) { sum[rt]=sum[rt<<1]+sum[rt<<1|1]; tot[rt]=tot[rt<<1]+tot[rt<<1|1]; } void BuildTree(int l,int r,int rt) { tree[rt].l=l; tree[rt].r=r; tree[rt].f=0; if(l==r) { tot[rt]=V[l+1]-V[l]; sum[rt]=0; return; } int mid=(tree[rt].l+tree[rt].r)/2; BuildTree(l,mid,rt<<1); BuildTree(mid+1,r,rt<<1|1); PushUp(rt); } void Update(int c,int l,int r,int rt) { if(tree[rt].l==l&&tree[rt].r==r) { tree[rt].f+=c; // cout<<V[l]<<" "<<V[r+1]<<" "<<tree[rt].f<<endl; if(tree[rt].f>0) sum[rt]=tot[rt]; else sum[rt]=0; } if(tree[rt].l==tree[rt].r) return; int mid=(tree[rt].l+tree[rt].r)/2; if(r<=mid) Update(c,l,r,rt<<1); else if(l>mid)Update(c,l,r,rt<<1|1); else { Update(c,l,mid,rt<<1); Update(c,mid+1,r,rt<<1|1); } PushUp(rt); } bool cmp(node2 a,node2 b) { if(a.h!=b.h) return a.h<b.h; else if(a.l!=b.l) return a.l<b.l; return a.r<b.r; } int n,cnt,Case=0;; double x1,x2,y1,y2,ans; int main() { while(scanf("%d",&n)&&n) { Case++; ans=0; cnt=0; V.clear(); V.push_back(-1); for(int i=1;i<=n;i++) { scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); ++cnt; line[cnt].l=x1,line[cnt].r=x2,line[cnt].h=y1,line[cnt].flag=1;//分出所有入边 ++cnt; line[cnt].l=x1,line[cnt].r=x2,line[cnt].h=y2,line[cnt].flag=-1;//分出所有出边 V.push_back(x1); V.push_back(x2); } sort(V.begin(),V.end()); V.erase(unique(V.begin(),V.end()),V.end()); sort(line+1,line+cnt+1,cmp);//将边按纵坐标进行排列 int len=V.size()-1; BuildTree(1,len,1); // cout<<cnt<<endl; for(int i=1;i<=cnt;i++) { if(i>1) ans+=sum[1]*(line[i].h-line[i-1].h); Update(line[i].flag,get_id(line[i].l),get_id(line[i].r)-1,1); // cout<<sum[1]<<" "<<ans<<endl; } printf("Test case #%d\n",Case); printf("Total explored area: %.2f\n\n",ans); } return 0; }
标签:corn 排列 back nio test res ble should val
原文地址:https://www.cnblogs.com/a249189046/p/9668272.html