bzoj2300【HAOI2011】防线修建

题目描述

近来A国和B国的矛盾激化,为了预防不测,A国准备修建一条长长的防线,当然修建防线的话,肯定要把需要保护的城市修在防线内部了。可是A国上层现在还犹豫不决,到底该把哪些城市作为保护对象呢?又由于A国的经费有限,所以希望你能帮忙完成如下的一个任务:

1.给出你所有的A国城市坐标

2.A国上层经过讨论,考虑到经济问题,决定取消对i城市的保护,也就是说i城市不需要在防线内了

3.A国上层询问对于剩下要保护的城市,修建防线的总经费最少是多少

你需要对每次询问作出回答。注意单位1长度的防线花费为1。

A国的地形是这样的,形如下图,x轴是一条河流,相当于一条天然防线,不需要你再修建

A国总是有两个城市在河边,一个点是(0,0),一个点是(n,0),其余所有点的横坐标均大于0小于n,纵坐标均大于0。A国有一个不在(0,0)和(n,0)的首都。(0,0),(n,0)和首都这三个城市是一定需要保护的。

上图中,A,B,C,D,E点为A国城市,且目前都要保护,那么修建的防线就会是A-B-C-D,花费也就是线段AB的长度+线段BC的长度+线段CD的长度,如果,这个时候撤销B点的保护,那么防线变成下图


输入格式

第一行,三个整数n,x,y分别表示河边城市和首都是(0,0),(n,0),(x,y)。

第二行,一个整数m。

接下来m行,每行两个整数a,b表示A国的一个非首都非河边城市的坐标为(a,b)。

再接下来一个整数q,表示修改和询问总数。

接下来q行每行要么形如1 i,要么形如2,分别表示撤销第i个城市的保护和询问。


输出格式

对于每个询问输出1行,一个实数v,表示修建防线的花费,保留两位小数


提示

m<=100000,q<=200000,n>1

所有点的坐标范围均在10000以内, 数据保证没有重点


  • 题解:

    • 考虑倒着把点插入凸包;
    • 只需要每次找到点在原凸包的$x$坐标前驱后继删掉不构成凸包的再插入;
    • 可以用$splay$维护即可(常数不太好看)
    •   1 #include<cstdio>
        2 #include<iostream>
        3 #include<algorithm>
        4 #include<cstring>
        5 #include<queue>
        6 #include<cmath>
        7 #include<vector>
        8 #include<stack>
        9 #include<map>
       10 #include<set>
       11 #define Run(i,l,r) for(int i=l;i<=r;i++)
       12 #define Don(i,l,r) for(int i=l;i>=r;i--)
       13 #define ll long long
       14 #define ld double
       15 #define inf 0x3f3f3f3f
       16 #define mk make_pair
       17 #define fir first
       18 #define sec second
       19 #define il inline
       20 #define rg register
       21 #define pb push_back
       22 using namespace std;
       23 const int N=100010;
       24 int n,m,mx,tx,ty,ch[N][2],sz[N],fa[N],vis[N],rt,cnt;
       25 ld now,ans[N<<1];
       26 il char gc(){
       27     static char*p1,*p2,s[1000000];
       28     if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin);
       29     return(p1==p2)?EOF:*p1++;
       30 }
       31 il int rd(){
       32     int x=0; char c=gc();
       33     while(c<‘0‘||c>‘9‘)c=gc();
       34     while(c>=‘0‘&&c<=‘9‘)x=(x<<1)+(x<<3)+c-‘0‘,c=gc();
       35     return x;
       36 }
       37 struct poi{
       38     int x,y;
       39     poi(int _x=0,int _y=0):x(_x),y(_y){};
       40     bool operator <(const poi&A)const{return x==A.x?y<A.y:x<A.x;}
       41     poi operator -(const poi&A)const{return poi(x-A.x,y-A.y);}
       42 }p[N],q[N],Q[N<<1];
       43 int crs(poi A,poi B){return A.x*B.y-A.y*B.x;}
       44 int dot(poi A,poi B){return A.x*B.x+A.y*B.y;}
       45 ld dis(poi A){return sqrt(A.x*A.x+A.y*A.y);}
       46 il void update(int x){sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;}
       47 il void rotate(int x,int&k){
       48     int y=fa[x],z=fa[y];
       49     if(y==k)k=x;else ch[z][ch[z][1]==y]=x;
       50     int l=ch[y][1]==x,r=l^1;
       51     fa[x]=z;fa[y]=x;fa[ch[x][r]]=y;
       52     ch[y][l]=ch[x][r],ch[x][r]=y;
       53     update(y);update(x);
       54 }
       55 il void splay(int x,int&k){
       56     for(int y,z;x!=k;rotate(x,k)){
       57         y=fa[x],z=fa[y];
       58         if(y!=k)rotate( (ch[y][0]==x)^(ch[z][0]==y) ? x : y ,k);
       59     }
       60 }
       61 il void ins(int&k,int x){
       62     if(!k)q[k=++cnt]=p[x];
       63     else {
       64         if(p[x]<q[k])ins(ch[k][0],x),fa[ch[k][0]]=k;
       65         else ins(ch[k][1],x),fa[ch[k][1]]=k;
       66     }
       67     update(k);
       68 }
       69 il int find_pre(int k,int x){
       70     int re=0;
       71     while(k){
       72         if(q[k]<p[x])re=k,k=ch[k][1];
       73         else k=ch[k][0];
       74     }
       75     return re;
       76 }
       77 il int find_nxt(int k,int x){
       78     int re=0;
       79     while(k){
       80         if(p[x]<q[k])re=k,k=ch[k][0];
       81         else k=ch[k][1];
       82     }
       83     return re;
       84 }
       85 il void insert(int x){
       86     int T1=find_pre(rt,x),T2=find_nxt(rt,x),t1,t2;
       87     if(crs(p[x]-q[T1],q[T2]-p[x])>=0)return;
       88     now -= dis(q[T1]-q[T2]);
       89     for(splay(t1=T1,rt),t2=ch[t1][0];sz[t2];){
       90         while(ch[t2][1])t2=ch[t2][1];
       91         splay(t2,ch[t1][0]);
       92         if(crs(q[t1]-q[t2],p[x]-q[t1])>=0){
       93             now -= dis(q[t1]-q[t2]);
       94             fa[ch[t2][1]=ch[t1][1]]=t2;
       95             update(rt=t2);
       96             t1=t2,t2=ch[t1][0];
       97         }else break;
       98     }
       99     now += dis(p[x]-q[t1]);
      100     for(splay(t1=T2,rt),t2=ch[t1][1];sz[t2];){
      101         while(ch[t2][0])t2=ch[t2][0];
      102         splay(t2,ch[t1][1]);
      103         if(crs(q[t1]-q[t2],p[x]-q[t1])<=0){
      104             now -= dis(q[t1]-q[t2]);
      105             fa[ch[t2][0]=ch[t1][0]]=t2;
      106             update(rt=t2);
      107             t1=t2,t2=ch[t1][1];
      108         }else break;
      109     }
      110     now += dis(p[x]-q[t1]);
      111     ins(rt,x);
      112 }
      113 int main(){
      114     #ifndef ONLINE_JUDGE
      115     freopen("bzoj2300.in","r",stdin);
      116     freopen("bzoj2300.out","w",stdout);
      117     #endif
      118     mx=rd();tx=rd();ty=rd();n=rd();
      119     for(int i=1;i<=n;++i)p[i].x=rd(),p[i].y=rd();
      120     p[0]=poi(0,0);ins(rt,0);
      121     p[n+1]=poi(mx,0);ins(rt,n+1);
      122     p[n+2]=poi(tx,ty);ins(rt,n+2);
      123     now = dis(p[0]-p[n+2]) + dis(p[n+1]-p[n+2]);
      124     m=rd();for(int i=1;i<=m;++i){Q[i].x=rd();if(Q[i].x&1)vis[Q[i].y=rd()]=1;}
      125     for(int i=1;i<=n;++i)if(!vis[i])insert(i);
      126     for(int i=m;i;--i)if(Q[i].x&1)insert(Q[i].y);else ans[i]=now;
      127     for(int i=1;i<=m;++i)if(Q[i].x==2)printf("%.2lf\n",ans[i]);
      128     return 0;
      129 }//by tkys_Austin;

      bzoj2300

原文地址:https://www.cnblogs.com/Paul-Guderian/p/10269978.html

时间: 2024-11-10 18:20:21

bzoj2300【HAOI2011】防线修建的相关文章

bzoj千题计划236:bzoj2300: [HAOI2011]防线修建

http://www.lydsy.com/JudgeOnline/problem.php?id=2300 维护动态凸包,人懒用的set 用叉积判断,不要用斜率 #include<set> #include<cmath> #include<cstdio> #include<iostream> using namespace std; #define N 100001 struct node { int x,y; node(int x_=0,int y_=0):

BZOJ-2300 [HAOI2011]防线修建

将问题离线倒序处理,问题变成动态加点维护凸包. #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <iostream> #include <cctype> #include <set> #define rep(i, l, r) for(int i=l; i&

【BZOJ2300】[HAOI2011]防线修建 set维护凸包

[BZOJ2300][HAOI2011]防线修建 Description 近来A国和B国的矛盾激化,为了预防不测,A国准备修建一条长长的防线,当然修建防线的话,肯定要把需要保护的城市修在防线内部了.可是A国上层现在还犹豫不决,到底该把哪些城市作为保护对象呢?又由于A国的经费有限,所以希望你能帮忙完成如下的一个任务: 1.给出你所有的A国城市坐标 2.A国上层经过讨论,考虑到经济问题,决定取消对i城市的保护,也就是说i城市不需要在防线内了 3.A国上层询问对于剩下要保护的城市,修建防线的总经费最少

BZOJ 2300: [HAOI2011]防线修建( 动态凸包 )

离线然后倒着做就变成了支持加点的动态凸包...用平衡树维护上凸壳...时间复杂度O(NlogN) ----------------------------------------------------------------------- #include<cmath> #include<cstdio> #include<cctype> #include<cstring> #include<cstdlib> #include<algori

【BZOJ 2300】 2300: [HAOI2011]防线修建 (动态凸包+set)

2300: [HAOI2011]防线修建 Description 近来A国和B国的矛盾激化,为了预防不测,A国准备修建一条长长的防线,当然修建防线的话,肯定要把需要保护的城市修在防线内部了.可是A国上层现在还犹豫不决,到底该把哪些城市作为保护对象呢?又由于A国的经费有限,所以希望你能帮忙完成如下的一个任务: 1.给出你所有的A国城市坐标 2.A国上层经过讨论,考虑到经济问题,决定取消对i城市的保护,也就是说i城市不需要在防线内了 3.A国上层询问对于剩下要保护的城市,修建防线的总经费最少是多少

【题解】P2521 [HAOI2011]防线修建(动态凸包)

[题解]P2521 [HAOI2011]防线修建(动态凸包) 凸包是易插入不好删除的东西,按照剧情所以我们时光倒流 然后问题就是维护凸包的周长,支持加入 本来很简单,但是计算几何就是一些小地方经验不足容易WA和RE 然后代码注释里有一些经验 //@winlere #include<iostream> #include<set> #include<cstdio> #include<cstring> #include<algorithm> #incl

cogs 547:[HAOI2011] 防线修建

★★★☆   输入文件:defense.in   输出文件:defense.out   简单对比 时间限制:1 s   内存限制:128 MB 题目描述: 近来A国和B国的矛盾激化,为了预防不测,A国准备修建一条长长的防线,当然修建防线的话,肯定要把需要保护的城市修在防线内部了.可是A国上层现在还犹豫不决,到底该把哪些城市作为保护对象呢?又由于A国的经费有限,所以希望你能帮忙完成如下的一个任务: 给出你所有的A国城市坐标 A国上层经过讨论,考虑到经济问题,决定取消对i城市的保护,也就是说i城市不

BZOJ [HAOI2011]防线修建(动态凸包)

听说有一种很高端的东西叫动态凸包维护dp就像学一下,不过介于本人还不会动态凸包就去学了下,还是挺神奇的说,维护上下凸包的写法虽然打得有点多不过也只是维护复制黏贴的事情而已罢了. 先说下动态凸包怎么写吧,搞棵平衡树存上下凸壳然后每次插入一个点就往他左右维护看是否满足凸性否则就弹出,就是这么简单 这道题就是删点然后询问凸壳,那么离线反着做就行了 出题人还是挺良心的直接让你维护上凸壳就行了,还不用管边界条件 用set打了一下,比较慢但还是挺好打的= = 换新blog挺多功能得试试的,现在想搞个像HZW

[日常摸鱼]Luogu2521[HAOI2011]防线修建-set维护凸包

https://www.luogu.org/problemnew/show/2521 题意:维护一个上凸包:删点,查询周长 很容易想到把问题转换为离线:先读入全部操作,记录下最后剩下的点,倒着加点来维护凸包,同时也倒着做询问. 然后问题就变成了怎么维护加点的操作,这题其实只要维护上半个凸包(其实也有一点启发性了吧),用set存凸包的点集,对于要加的点往左右两边一直把不行的点删掉就好了,因为一个点最多被删一次所以加上set的$log$实际复杂度是$O(nlog n)$的而不是$O(n^2)$. 如

Luogu-2521 [HAOI2011]防线修建

倒过来处理所有询问,就变成了一道动态凸包的裸题 吐槽一下这道题只要维护上凸壳就好了,我zz了没好好看题打了两个2333 // luogu-judger-enable-o2 #include<set> #include<cmath> #include<cstdio> #include<cstring> #include<algorithm> #define rp (*r) #define lp (*l) #define rrp (*rr) #def