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。
举个例子
$$\begin{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\nTotal explored area: %.2f\n\n",q++,res);
}
return 0;
}