luogu2521 [HAOI2011]防线修建

来源:互联网 发布:深红色房间 知乎 编辑:程序博客网 时间:2024/04/30 10:50

【题目】
  点击传送
【题解1】

  题意就是给你一大堆点,要你求出凸包,然后每次可以删除一个点,问你删除之后的周长是多少。

  对于30%,可以每删除一个点,就重新求凸包,复杂度O(N^2lbN)。

  对于100%,考虑当你删掉一个点时,那么这个点原来连接的左右两点一定还在凸包上,而凸包有变化的区域只限于这两点之间(以极角序为参考),所以你就可以在这个区间里进行局部的凸包重建。这个做法的复杂度很玄学,当数据极端的时候会被卡掉的,但是出题人显然没考虑到这一点,轻松AC了。

【题解2】

  听说这道题正解是,先读入所有操作,倒着看,就成了你要往凸包上插入一些点。然后用平衡树维护凸包,每次插入一个点,找到它按极角序应该在的位置,然后判断其左右会不会被覆盖(用叉积),用类似Graham的思想来做就好了。这样复杂度是O(NlbN)。网上大部分人都是用的set。

【代码(第一种算法)】

//凸包#include <cstdio>#include <cmath>#include <algorithm>#define maxn 100010using namespace std;struct vec{double x,y;int num;}p[maxn];double C;int N, top, left[maxn], right[maxn], s[maxn], table[maxn], on[maxn];double cp(vec v1, vec v2){return v1.x*v2.y-v2.x*v1.y;}bool cmp(vec p1, vec p2){double c=cp(p1,p2);return c==0?p1.x<p2.x or p1.y<p2.y:c>0;}void graham(){int i;vec v1, v2;s[++top]=1;on[1]=true;sort(p+2,p+N+1,cmp);for(i=2;i<=N;i++){v1=(vec){p[s[top]].x-p[s[top-1]].x,p[s[top]].y-p[s[top-1]].y,0};v2=(vec){p[i].x-p[s[top]].x,p[i].y-p[s[top]].y,0};while(top>1 and cp(v1,v2)<0){on[s[top--]]=false;v1=(vec){p[s[top]].x-p[s[top-1]].x,p[s[top]].y-p[s[top-1]].y,0};v2=(vec){p[i].x-p[s[top]].x,p[i].y-p[s[top]].y,0};}right[i]=s[top];left[s[top]]=i;s[++top]=i;on[i]=true;}for(i=N-1;p[i].x*p[s[top]].y-p[i].y*p[s[top]].x==0;i--)right[i]=s[top],left[s[top]]=i,s[++top]=i;right[s[1]]=s[top];left[s[top]]=s[1];}double dist(vec p1, vec p2){double t1=p1.x-p2.x, t2=p1.y-p2.y;return sqrt(t1*t1+t2*t2);}void del(int num){int l=left[num], r=right[num], i, x;vec v1, v2;p[num].num=-1;if(!on[num])return;else on[num]=false;C-=dist(p[num],p[l])+dist(p[num],p[r]);s[top=1]=r;x=l==N?1:l+1;for(i=r+1;i!=x;i=i==N?1:i+1){if(p[i].num==-1)continue;v1=(vec){p[s[top]].x-p[s[top-1]].x,p[s[top]].y-p[s[top-1]].y,0};v2=(vec){p[i].x-p[s[top]].x,p[i].y-p[s[top]].y,0};while(top>1 and cp(v1,v2)<0){on[s[top--]]=false;v1=(vec){p[s[top]].x-p[s[top-1]].x,p[s[top]].y-p[s[top-1]].y,0};v2=(vec){p[i].x-p[s[top]].x,p[i].y-p[s[top]].y,0};}right[i]=s[top];left[s[top]]=i;s[++top]=i;on[i]=true;}for(i=2;i<=top;i++)C+=dist(p[s[i]],p[s[i-1]]);}int main(){int x, y, q, i, a;scanf("%d%d%d",&a,&x,&y);p[1].x=p[1].y=0;p[2].x=a,p[2].y=0;p[3].x=x,p[3].y=y;scanf("%d",&N),N+=3;for(i=4;i<=N;i++)scanf("%lf%lf",&p[i].x,&p[i].y),p[i].num=i-3;graham();for(i=1;i<=N;i++)table[p[i].num]=i;for(C=dist(p[s[1]],p[s[top]]),i=2;i<=top;i++)C+=dist(p[s[i]],p[s[i-1]]);C-=a; scanf("%d",&q);for(i=1;i<=q;i++){scanf("%d",&x);if(x==1)scanf("%d",&y),del(table[y]);else printf("%.2lf\n",C);}return 0;}


0 0
原创粉丝点击