您的位置:首页 > 运维架构

bzoj 2300: [HAOI2011]防线修建(splay动态维护凸包)

2016-09-10 14:26 597 查看

2300: [HAOI2011]防线修建

Time Limit: 10 Sec  Memory Limit: 512 MB

Submit: 800  Solved: 440

[Submit][Status][Discuss]

Description

近来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点的保护,那么防线变成下图



Input

第一行,三个整数n,x,y分别表示河边城市和首都是(0,0),(n,0),(x,y)。
第二行,一个整数m。
接下来m行,每行两个整数a,b表示A国的一个非首都非河边城市的坐标为(a,b)。
再接下来一个整数q,表示修改和询问总数。
接下来q行每行要么形如1 i,要么形如2,分别表示撤销第i个城市的保护和询问。

Output

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

Sample Input

4 2 1

2

1 2

3 2

5

2

1 1

2

1 2

2

Sample Output

6.47

5.84

4.47

HINT

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

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

Source



[Submit][Status][Discuss]

题解:splay动态维护凸包。

因为删点不好操作,所以我们把数据离线,然后倒序处理,把删点操作变成加点操作。

用splay维护凸包中的点横坐标有序,插入一个点,如果(x,pre(x))的斜率小于(x,next(x))的斜率的话(注意特判横坐标相等的情况),说明形成的了一个凹陷的角,不满足凸包,直接删去刚插入的点即可。

否则,我们需要从这个点的左边找到第一条斜率(x,pre(x))<斜率(pre(x),pre(pre(x)))的边,不断的删去中间不满足的点,顺便更新答案。

从这个点的右边找到右边第一个斜率(x,next(x))>斜率(next(x),next(next(x)))的边,不断删除中间不满足的点。

需要注意的是在向左寻找的时候,如果两个点横坐标相同,斜率需要返回最大值,向右寻找的时候需要返回最小值。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 200003
#define inf 1000000000
using namespace std;
int fa
,ch
[3],xl
,yl
,n,m,pd
,root;
double ans
,ans1,ks
,ks1
;
struct point
{
double x,y;
}p
;
struct data
{
int opt,x;
}a
;
int get(int x)
{
return ch[fa[x]][1]==x;
}
void clear(int x)
{
fa[x]=ch[x][0]=ch[x][1]=0;
}
void rotate(int x)
{
int y=fa[x]; int z=fa[y]; int which=get(x);
ch[y][which]=ch[x][which^1]; fa[ch[x][which^1]]=y;
ch[x][which^1]=y; fa[y]=x;
if (z) ch[z][ch[z][1]==y]=x;
fa[x]=z;
}
void splay(int x,int tar)
{
for (int f;(f=fa[x])!=tar;rotate(x))
if (fa[f]!=tar)
rotate(get(x)==get(f)?f:x);
if (!tar) root=x;
}
void solve(double x,double y,int k)
{
if (!root)
{
root=k; fa[k]=ch[k][0]=ch[k][1]=0;
return;
}
int now=root,f;
while (true)
{
f=now;
now=ch[now][x>p[now].x];
if (!now)
{
fa[k]=f; ch[f][x>p[f].x]=k;
splay(k,0); return;
}
}
}
int pre(int now)
{
now=ch[now][0];
while (ch[now][1]) now=ch[now][1];
return now;
}
int next(int now)
{
now=ch[now][1];
while (ch[now][0]) now=ch[now][0];
return now;
}
void del(int now)
{
if (!ch[now][0]&&!ch[now][1])
{
clear(now); root=0; return;
}
if (!ch[now][0])
{
int ordr=now; now=ch[now][1]; fa[now]=0; clear(ordr); return;
}
if (!ch[now][1])
{
int ordr=now; now=ch[now][0]; fa[now]=0; clear(ordr); return;
}
int t=pre(now),oldr=root;
splay(t,0); fa[ch[oldr][1]]=root; ch[root][1]=ch[oldr][1]; clear(oldr);
}
double getdis(int x,int y)
{
int t=p[x].x-p[y].x;
int t1=p[y].y-p[x].y;
return sqrt(t*t+t1*t1);
}
double getk(int x,int y,int opt)
{
if (p[x].x==p[y].x)
if (opt==1) return inf;
else return -inf;
return (p[x].y-p[y].y)/(p[x].x-p[y].x);
}
void insert(double x,double y,int k)
{
solve(x,y,k);
int l=pre(k); int r=next(k);
if (!l||!r) return;
splay(l,k); splay(r,k);
if(p[l].x!=p[k].x&&p[k].x!=p[r].x&&getk(l,k,1)<=getk(k,r,1)||(p[k].x==p[l].x&&p[k].y<=p[l].y)||(p[k].x==p[r].x&&p[k].y<=p[r].y))
{
del(k);
return;
}
ans1-=getdis(l,r);
ks[k]=getk(l,k,1); ks[r]=getk(k,r,1);
ks1[k]=getk(k,r,2); ks1[l]=getk(l,k,2);
ans1+=getdis(l,k); ans1+=getdis(k,r);
int now=k;
while(ks[now]>=ks[l]&&l!=1)
{
ans1-=getdis(now,l); splay(l,0); ans1-=getdis(l,pre(l));
del(l); splay(now,0); l=pre(now);
//splay(l,now);
ks[now]=getk(l,now,1);
ks1[l]=getk(l,now,2);
ans1+=getdis(l,now);
}
while (ks1[now]<=ks1[r]&&r!=2)
{
ans1-=getdis(now,r); splay(r,0); ans1-=getdis(r,next(r));
del(r); splay(now,0); r=next(now);
//splay(r,now);
ks1[now]=getk(now,r,2);
ks[r]=getk(now,r,1);
ans1+=getdis(now,r);
}
}
int main()
{
freopen("a.in","r",stdin);
freopen("my.out","w",stdout);
int x1,y1;
scanf("%d%d%d",&n,&x1,&y1);
p[1].x=0; p[1].y=0; p[2].x=n; p[2].y=0; p[3].x=x1; p[3].y=y1;
insert(0,0,1);
insert(n,0,2); ans1+=getdis(1,2); ks[1]=inf; ks1[2]=-inf;
insert(x1,y1,3);
scanf("%d",&m);
for (int i=4;i<=m+3;i++)
scanf("%lf%lf",&p[i].x,&p[i].y);
int t; scanf("%d",&t);
for (int i=1;i<=t;i++)
{
scanf("%d",&a[i].opt);
if (a[i].opt==1) scanf("%d",&a[i].x),a[i].x+=3,pd[a[i].x]=1;
}
for (int i=4;i<=m+3;i++)
if (!pd[i]) insert(p[i].x,p[i].y,i);
int cnt=0;
for (int i=t;i>=1;i--)
{
if (a[i].opt==1) {
int k=a[i].x;
insert(p[k].x,p[k].y,k);
}
else ans[++cnt]=ans1;
}
for (int i=cnt;i>=1;i--)
printf("%0.2lf\n",ans[i]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: