【[ZJOI2008]瞭望塔】维护半平面交交线
比较特殊的维护半平面交下凸壳。
luogu2600
我们可以用一条山的上方轮廓折线(x1, y1), (x2, y2), …. (xn, yn)来描述H村的形状,这里x1 < x2 < …< xn。瞭望塔可以建造在[x1, xn]间的任意位置, 但必须满足从瞭望塔的顶端可以看到H村的任意位置。可见在不同的位置建造瞭望塔,所需要建造的高度是不同的。为了节省开支,dadzhi村长希望建造的塔高度尽可能小。
请你写一个程序,帮助dadzhi村长计算塔的最小高度。
题目描述
致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安。 我们将H村抽象为一维的轮廓。如下图所示
输入输出格式
输入格式: 输入文件tower.in第一行包含一个整数n,表示轮廓折线的节点数目。接下来第一行n个整数, 为x1 ~ xn. 第三行n个整数,为y1 ~ yn。 输出格式: 输出文件tower.out仅包含一个实数,为塔的最小高度,精确到小数点后三位。输入输出样例
说明
对于60%的数据, N ≤ 60; 对于100%的数据, N ≤ 300,输入坐标绝对值不超过106,注意考虑实数误差带来的问题。 由于只有一条路线以上的部分才能看过来,那么就是一个半平面交。这道题比较特殊,所有的都是直线,类似于bzoj1007,维护下凸壳。可以考虑到最后的答案要么是在凸壳交点或者路的交点处。 我们把所有直线提出来。先按照斜率排序,同斜率按照截距排序。 然后如果一条直线和另一条直线斜率相同显然选截距更大的,而如果斜率更大的直线于上上条直线交点前于斜率更小的直线交点前,那么后一条直线也没用。这样考虑完之后就求出了半平面交下凸壳。//维护下凸壳,类同bzoj1007 #include<cstdio> #include<algorithm> #include<cmath> #include<iostream> using namespace std; typedef double db; const db eps = 1e-8; const int maxn = 605; struct pt{ db x,y; }z[maxn]; pt operator+(pt a,pt b) { return (pt){a.x+b.x,a.y+b.y}; } pt operator-(pt a,pt b) { return (pt){a.x-b.x,a.y-b.y}; } pt operator*(db k,pt a) { return (pt){k*a.x,k*a.y}; } db operator*(pt a,pt b) { return a.x*b.x+a.y*b.y; } db operator^(pt a,pt b) { return a.x*b.y-a.y*b.x; } bool operator<(pt aa,pt bb) { if(fabs(aa.x-bb.x)<eps) return aa.y < bb.y; return aa.x < bb.x; } int n,tot; struct line{ db k,b; }st[maxn],orz[maxn]; bool operator<(line aa,line bb) { if(fabs(aa.k-bb.k)<eps) return aa.b < bb.b; return aa.k < bb.k; } db getx(line aa,line bb) { return (aa.b-bb.b)/(bb.k-aa.k); } line getline(pt a,pt b) { line tmp; tmp.k = (b.y-a.y)/(b.x-a.x); tmp.b = b.y - tmp.k*b.x; return tmp; } void CUT(line aa) { int o = 0; while(tot) { if(fabs(st[tot].k-aa.k)<eps) { --tot; continue; } if(tot>1&&getx(aa,st[tot-1]) < getx(st[tot-1],st[tot]) + eps ) { --tot; continue; } break; } st[++tot] = aa; } db getup(db x) { db oo = -1e17; for(int i=1;i<=tot;i++) { oo = max(oo,st[i].k*x+st[i].b); } return oo; } db getdown(db x) { int p = lower_bound(z+1,z+1+n,(pt){x,-1e18})-z; if(p==n+1||p==1) return -1e18; line tt = getline(z[p],z[p-1]); return tt.k*x+tt.b; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%lf",&z[i].x); } for(int i=1;i<=n;i++) { scanf("%lf",&z[i].y); } for(int i=1;i<n;i++) { orz[i] = getline(z[i],z[i+1]); } int oo = n-1; sort(orz+1,orz+1+oo); for(int i=1;i<=oo;i++) CUT(orz[i]); db ans = 1e17; for(int i=1;i<=n;i++) { ans = min(ans,getup(z[i].x)-z[i].y); } for(int i=1;i<tot;i++) { db xx = getx(st[i],st[i+1]); ans = min(ans,st[i].k*xx+st[i].b-getdown(xx)); } printf("%.3lf",ans); }