BZOJ2300: [HAOI2011]防线修建
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2300
(我只是在发以前写过的题。。
因为题目没说强制在线,所以离线乱搞就可以了。先把点删掉然后一个一个插进去,维护一个动态凸包就可以了。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cmath> #include<set> #define esp 1e-7 #define ll long long #define oo 1152921504606846976 #define rep(i,l,r) for (int i=l;i<=r;i++) #define down(i,l,r) for (int i=l;i>=r;i--) using namespace std; const int maxn=200500,maxm=17; struct P{int x,y; }a[maxn],del[maxn]; set<P> q; double now,ans[maxn]; int top,n,m,mark[maxn],t1,t2,b[maxn]; ll read(){ int x=0,f=1; char ch=getchar(); while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();} while (isdigit(ch)) x=x*10+ch-'0',ch=getchar(); return x*f; } P operator -(P a,P b){ return (P){a.x-b.x,a.y-b.y}; } double operator *(P a,P b){ return (a.x*b.y-a.y*b.x); } int cmp(double x){ if (fabs(x)<esp) return 0; if (x>0) return 1; return -1; } double dis(P a,P b){ return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } bool operator <(P a,P b){ return a.x<b.x||(a.x==b.x&&a.y<b.y); } void insert(P x){ set<P>::iterator r=q.lower_bound(x),l=r,t; l--; if ((*r-*l)*(x-*l)<0) return; now-=dis(*l,*r); while (1){ t=r++; if (r==q.end()) break; if ((*r-x)*(*t-x)>0) break; now-=dis(*r,*t); q.erase(t); } while (l!=q.begin()){ t=l--; if ((*t-x)*(*l-x)>0) break; now-=dis(*l,*t); q.erase(t); } q.insert(x); l=r=q.find(x); l--;r++; now+=dis(*r,x)+dis(*l,x); } int main(){ int op,x; n=read(); P bas; bas.x=read(); bas.y=read(); q.insert((P){0,0}); q.insert((P){n,0}); q.insert(bas); now+=dis((P){0,0},bas)+dis((P){n,0},bas); m=read(); rep(i,1,m) a[i].x=read(),a[i].y=read(); int Q; Q=read(); rep(i,1,Q){ op=read(); if (op==1) {x=read();del[++t1]=a[x]; mark[x]=1;} else b[++t2]=t1; } rep(i,1,m) if (!mark[i]) insert(a[i]); int t=t1; down(i,t2,1){ while (t>b[i]) insert(del[t--]); ans[i]=now; } rep(i,1,t2) printf("%.2lf\n",ans[i]); return 0; }