BZOJ2300[HAOI2011]防线修建——非旋转treap+凸包(平衡树动态维护凸包)
题目描述

上图中,A,B,C,D,E点为A国城市,且目前都要保护,那么修建的防线就会是A-B-C-D,花费也就是线段AB的长度+线段BC的长度+线段CD的长度,如果,这个时候撤销B点的保护,那么防线变成下图
输入
输出
对于每个询问输出1行,一个实数v,表示修建防线的花费,保留两位小数
样例输入
2
1 2
3 2
5
2
1 1
2
1 2
2
样例输出
5.84
4.47
提示
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
struct lty
{
int x,y;
lty(int X=0,int Y=0){x=X,y=Y;}
bool operator <(const lty &a)const{return x==a.x?y<a.y:x<a.x;}
lty operator -(const lty &a)const{return lty(x-a.x,y-a.y);}
}p[100010],s[100010],st[100010],tr[100010];
int cnt;
int top;
int tot;
int x,y;
int root;
int n,m,Q;
int ls[100010];
int rs[100010];
int r[100010];
int size[100010];
double ans;
int a,b,c,d;
int vis[100010];
struct yzl
{
int opt,id;
double res;
}q[200010];
ll cross(lty a,lty b)
{
return 1ll*a.x*b.y-1ll*a.y*b.x;
}
int newnode(int x,int y)
{
int rt=++cnt;
tr[rt].x=x;
tr[rt].y=y;
r[rt]=rand();
size[rt]=1;
return rt;
}
void pushup(int rt)
{
size[rt]=size[ls[rt]]+size[rs[rt]]+1;
}
double dis(lty a,lty b)
{
lty c=a-b;
return sqrt(1ll*c.x*c.x+1ll*c.y*c.y);
}
int merge(int x,int y)
{
if(!x||!y)
{
return x+y;
}
if(r[x]<r[y])
{
rs[x]=merge(rs[x],y);
pushup(x);
return x;
}
else
{
ls[y]=merge(x,ls[y]);
pushup(y);
return y;
}
}
void split_value(int rt,int &x,int &y,int k,int z)
{
if(!rt)
{
x=y=0;
return ;
}
if(tr[rt].x>k||(tr[rt].x==k&&tr[rt].y>z))
{
y=rt;
split_value(ls[rt],x,ls[y],k,z);
}
else
{
x=rt;
split_value(rs[rt],rs[x],y,k,z);
}
pushup(rt);
}
void split_left(int rt,int &x,int &y,int k)
{
if(!rt)
{
x=y=0;
return ;
}
if(size[ls[rt]]>=k)
{
y=rt;
split_left(ls[rt],x,ls[y],k);
}
else
{
x=rt;
split_left(rs[rt],rs[x],y,k-size[ls[rt]]-1);
}
pushup(rt);
}
void split_right(int rt,int &x,int &y,int k)
{
if(!rt)
{
x=y=0;
return ;
}
if(size[rs[rt]]>=k)
{
x=rt;
split_right(rs[rt],rs[x],y,k);
}
else
{
y=rt;
split_right(ls[rt],x,ls[y],k-size[rs[rt]]-1);
}
pushup(rt);
}
int build(int l,int r)
{
if(l==r)
{
return newnode(st[l].x,st[l].y);
}
int mid=(l+r)>>1;
return merge(build(l,mid),build(mid+1,r));
}
int main()
{
srand(12378);
scanf("%d%d%d",&n,&x,&y);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&p[i].x,&p[i].y);
}
p[m+1].x=x,p[m+1].y=y;
p[m+2].x=0,p[m+2].y=0;
p[m+3].x=n,p[m+3].y=0;
m+=3;
scanf("%d",&Q);
for(int i=1;i<=Q;i++)
{
scanf("%d",&q[i].opt);
if(q[i].opt==1)
{
scanf("%d",&q[i].id);
vis[q[i].id]=1;
}
}
for(int i=1;i<=m;i++)
{
if(!vis[i])
{
s[++tot]=p[i];
}
}
sort(s+1,s+1+tot);
for(int i=1;i<=tot;i++)
{
while(top>1&&cross(st[top-1]-st[top],s[i]-st[top])<=0)
{
top--;
}
st[++top]=s[i];
}
root=build(1,top);
for(int i=2;i<=top;i++)
{
ans+=dis(st[i-1],st[i]);
}
for(int i=Q;i>=1;i--)
{
if(q[i].opt==2)
{
q[i].res=ans;
}
else
{
int now=q[i].id;
split_value(root,a,d,p[now].x,p[now].y);
split_right(a,a,b,1);
split_left(d,c,d,1);
if(cross(tr[b]-p[now],tr[c]-p[now])<=0)
{
a=merge(a,b);
d=merge(c,d);
root=merge(a,d);
continue;
}
ans-=dis(tr[b],tr[c]);
a=merge(a,b);
d=merge(c,d);
split_right(a,a,c,1);
split_right(a,a,b,1);
while(b&&c&&cross(tr[b]-tr[c],p[now]-tr[c])<=0)
{
ans-=dis(tr[b],tr[c]);
c=b;
split_right(a,a,b,1);
}
ans+=dis(p[now],tr[c]);
a=merge(a,b);
a=merge(a,c);
split_left(d,b,d,1);
split_left(d,c,d,1);
while(b&&c&&cross(p[now]-tr[b],tr[c]-tr[b])<=0)
{
ans-=dis(tr[b],tr[c]);
b=c;
split_left(d,c,d,1);
}
ans+=dis(p[now],tr[b]);
d=merge(c,d);
d=merge(b,d);
root=merge(merge(a,newnode(p[now].x,p[now].y)),d);
}
}
for(int i=1;i<=Q;i++)
{
if(q[i].opt==2)
{
printf("%.2f\n",q[i].res);
}
}
}
BZOJ2300[HAOI2011]防线修建——非旋转treap+凸包(平衡树动态维护凸包)的更多相关文章
- 2019.02.21 bzoj2300: [HAOI2011]防线修建(set+凸包)
传送门 题意:动态维护凸包周长. 思路: 见这篇求面积的吧反正都是一个套路. 代码: #include<bits/stdc++.h> #define int long long #defi ...
- bzoj千题计划236:bzoj2300: [HAOI2011]防线修建
http://www.lydsy.com/JudgeOnline/problem.php?id=2300 维护动态凸包,人懒用的set 用叉积判断,不要用斜率 #include<set> ...
- BZOJ2300: [HAOI2011]防线修建
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2300 (我只是在发以前写过的题.. 因为题目没说强制在线,所以离线乱搞就可以了.先把点删掉然后 ...
- 非旋转Treap——普通平衡树
扔板跑…… #include<bits/stdc++.h> #define N 100010 #define mp make_pair using namespace std; typed ...
- 【BZOJ2300】[HAOI2011]防线修建 set维护凸包
[BZOJ2300][HAOI2011]防线修建 Description 近来A国和B国的矛盾激化,为了预防不测,A国准备修建一条长长的防线,当然修建防线的话,肯定要把需要保护的城市修在防线内部了.可 ...
- 【BZOJ 2300】 2300: [HAOI2011]防线修建 (动态凸包+set)
2300: [HAOI2011]防线修建 Description 近来A国和B国的矛盾激化,为了预防不测,A国准备修建一条长长的防线,当然修建防线的话,肯定要把需要保护的城市修在防线内部了.可是A国上 ...
- BZOJ 2300: [HAOI2011]防线修建( 动态凸包 )
离线然后倒着做就变成了支持加点的动态凸包...用平衡树维护上凸壳...时间复杂度O(NlogN) --------------------------------------------------- ...
- 【题解】P2521 [HAOI2011]防线修建(动态凸包)
[题解]P2521 [HAOI2011]防线修建(动态凸包) 凸包是易插入不好删除的东西,按照剧情所以我们时光倒流 然后问题就是维护凸包的周长,支持加入 本来很简单,但是计算几何就是一些小地方经验不足 ...
- 「BZOJ2300」[HAOI2011] 防线修建
传送门 操作离线之后倒着做,只有加点操作. 用set动态维护凸包即可. //Achen #include<algorithm> #include<iostream> #incl ...
随机推荐
- 浅谈SpringMVC执行过程
通过深入分析Spring源码,我们知道Spring框架包括大致六大模块, 如Web模块,数据库访问技术模块,面向切面模块,基础设施模块,核心容器模块和模块, 其中,在Spring框架的Web模块中,又 ...
- Linux网络技术管理及进程管理(week2_day4)--技术流ken
OSI七层模型和TCP/IP四层模型 OSI七层模型:OSI(Open System Interconnection)开放系统互连参考模型是国际标准化组织(ISO)制定的一个用于计算机或通信系统间互联 ...
- Vcomputer简介
1.Vcompter存储程序式计算机虚拟机软件简介 Vcompter存储程序式计算机虚拟机软件的文件名为comp_alpha(一般要先安装java运行环境,然后双击该软件即可运行),该软件是桂林电 ...
- 一个tomcat设置多个端口,多个端口对应多个应用
修改tomcat/conf目录里面server.xml文件 例如下面这样新增一个8090端口,设置下appBase目录,这样就可以用一个tomcat监听多个端口,每个端口都可以放应用了.我这样新增下面 ...
- Flask实战第3天:url_for使用
我们之前是通过url来找到对应的视图函数 / => hello_world 那么url_for则是通过视图函数找到url hello world => / 演示如下 #c ...
- QT通过url下载图片到本地
/* strUrl:下载图片时需要的url strFilePath:下载图片的位置(/home/XXX/YYY.png) */ void ThorPromote::downloadFileFromUr ...
- numpy 基础操作
Numpy 基础操作¶ 以numpy的基本数据例子来学习numpy基本数据处理方法 主要内容有: 创建数组 数组维度转换 数据选区和切片 数组数据计算 随机数 数据合并 数据统计计算 In [1]: ...
- sqlserver 2014使用时有Cannot find one or more components
好久没用sqlserver,今天打开却出现了一个错误,Cannot find one or more components,令人头疼.在启动Microsoft SQL Server Managemen ...
- Win32 Ime
Win32 Ime API: ImmGetContext: 获取指定窗口的当前的输入上下文,然后再尝试访问上下文中的信息.应用程序应该定期使用这个功能获取窗口的当前的输入上下文.若hWnd参数为零,将 ...
- Shell企业案例实战和企业面试题
shell企业面试题 1.批量创建带有随机小写字符文件程序 使用for循环在/pizza目录下创建10个html文件,其中每个文件包含10个随机小写字母加固定字母_pizza 1.思路分析: 核心是: ...