Atlantis
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 11551 Accepted Submission(s): 4906
The input file is terminated by a line containing a single 0. Don’t process it.
Output a blank line after each test case.
题目链接:HDU 1542
感觉难点就在如何用点树实现线段上的统计,首先这题是浮点数,肯定要离散化建树(我选的是对X坐标离散化),二分寻找下标当作区间[l,r]。
现在假设有两个区间段:1——2——3 与 3——4——5,但是如果用点树的方式进行更新对前面一个区间+1,后面一个区间-1,那会造成3这个点的覆盖次数变成0,但显然这两个区间在“段”上是连续的,这样更新肯定会出现问题,但是习惯上是写点树而不是段树,那只能对点修改一下,把更新区间的右端R减掉1,每个点表示这个点到后一个点的一段因此前面的两个区间变成了[1,2]与[3,4],这样在点上就不会出现重复的问题了,然后另外一点改动就是在pushup时直接向上传递不用pushdown。
举个例子
$$egin{array}{c|lll}
{下标}&{0}&{1}&{2}&{3}&{4}&{5}\
hline
{实际值}&{3.3}&{9.8}&{12.1}&{19.8}&{24.9}&{33.3}\
end{array}$$
这样的一个坐标离散化这时候出现一个线段[9.8~12.1],然后对应离散化的是[1,2-1]即[1,1],但统计len的时候显然是用12.1-9.8=2.3,因此统计时要用X[R+1]-X[L]来作为长度即X[2]-X[1],那这看起来似乎跟前面的刻意把右端点改成R-1矛盾了……既然统计要R+1那前面干嘛要R-1,其实R-1为的是不影响线段树的区间覆盖,但是你是知道实际上要用R来算,由于统计时是不会影响区间覆盖的,因此要还原回去即R=(R-1)+1
代码:
#include <stdio.h> #include <bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f #define CLR(arr,val) memset(arr,val,sizeof(arr)) #define LC(x) (x<<1) #define RC(x) ((x<<1)+1) #define MID(x,y) ((x+y)>>1) typedef pair<int,int> pii; typedef long long LL; const double PI=acos(-1.0); const int N=110; struct seg { int l,mid,r; int cnt; double len; }; struct Line { double l,r,h,flag; bool operator<(const Line &t)const { return h<t.h; } }; seg T[N<<3]; Line line[N<<1]; double xpos[N<<1]; inline void pushup(int k) { if(T[k].cnt) T[k].len=xpos[T[k].r+1]-xpos[T[k].l]; else { if(T[k].l==T[k].r) T[k].len=0; else T[k].len=T[LC(k)].len+T[RC(k)].len; } } void build(int k,int l,int r) { T[k].l=l; T[k].r=r; T[k].mid=MID(l,r); T[k].len=0.0; T[k].cnt=0; if(l==r) return ; build(LC(k),l,T[k].mid); build(RC(k),T[k].mid+1,r); } void update(int k,int l,int r,int flag) { if(l<=T[k].l&&T[k].r<=r) { T[k].cnt+=flag; pushup(k); } else { if(r<=T[k].mid) update(LC(k),l,r,flag); else if(l>T[k].mid) update(RC(k),l,r,flag); else update(LC(k),l,T[k].mid,flag),update(RC(k),T[k].mid+1,r,flag); pushup(k); } } int main(void) { int n,i,q=1; double xa,xb,ya,yb; while (~scanf("%d",&n)&&n) { int cnt_line=0; for (i=0; i<n; ++i) { scanf("%lf%lf%lf%lf",&xa,&ya,&xb,&yb); xpos[cnt_line]=xa; line[cnt_line]=(Line){xa,xb,ya,1}; ++cnt_line; xpos[cnt_line]=xb; line[cnt_line]=(Line){xa,xb,yb,-1}; ++cnt_line; } sort(xpos,xpos+cnt_line);//X轴坐标排序 sort(line,line+cnt_line);//线段排序 build(1,0,cnt_line); double res=0.0,dh; int l,r; for (i=0; i<cnt_line-1; ++i) { l=lower_bound(xpos,xpos+cnt_line,line[i].l)-xpos; r=lower_bound(xpos,xpos+cnt_line,line[i].r)-xpos; update(1,l,r-1,line[i].flag); dh=line[i+1].h-line[i].h; res+=dh*T[1].len; } printf("Test case #%d Total explored area: %.2f ",q++,res); } return 0; }