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 ...
随机推荐
- 粮草先行——Android折叠屏开发技术点(一)
最近有关折叠屏产品的新闻层出不穷,各家手机厂商也分别慢慢地亮出了自家的产品.然而市场上的一些APP仍然没有很好地适配这样的设备,显示不正常和应用重启的状况时有发生.因此,我会用接下来的几篇文章来点出有 ...
- 关于C#chart图表实现多条折线动态绑定数据的问题
之前就已经实现了多条折线绑定数据并显示,但不是动态绑定,而是每一条数据都要进行一次绑定,个人觉得在解决实际问题时,这样的解决方法过于笨重且缺乏扩展性,这次主要是对代码进行优化,实现写一遍代码,无论数据 ...
- String-StringBuffer-StringBuilder的区别和源码分析
一,String,StringBuffer,StringBuilder三者之间的关系 三个类的关系:StringBuffer和StringBuilder都继承自AbstractStringBuilde ...
- css 修改默认滚动条样式
来自:https://www.cnblogs.com/juqian/p/6273808.html 侵删 <div class="inner"> <div clas ...
- Python 使用python-kafka类库开发kafka生产者&消费者&客户端
使用python-kafka类库开发kafka生产者&消费者&客户端 By: 授客 QQ:1033553122 1.测试环境 python 3.4 zookeeper- ...
- 基于jwt的用户登录认证
最近在app的开发过程中,做了一个基于token的用户登录认证,使用vue+node+mongoDB进行的开发,前来总结一下. token认证流程: 1:用户输入用户名和密码,进行登录操作,发送登录信 ...
- Github入门详情教程
前言 之前我写了一篇文章<一篇文章了解Github和Git教程>还延伸了几篇阅读,对大部分小白很有用,那么我继续普及下Github页面及其概念. 定义 GitHub 是一个网站,一个面向开 ...
- Python第十四天 序列化 pickle模块 cPickle模块 JSON模块 API的两种格式
Python第十四天 序列化 pickle模块 cPickle模块 JSON模块 API的两种格式 目录 Pycharm使用技巧(转载) Python第一天 安装 shell 文件 Py ...
- Eclipse里JAR文件的打包和使用
作用:用于封装class.properties文件,是文件封装的最小单元: 包含Java类的普通库.资源(resources).辅助文件(auxiliary files)等. 可以将程 ...
- 搭建Hadoop的环境
准备实验的环境: 1.安装Linux.JDK 2.配置主机名.免密码登录 3.约定:安装目录:/usr/local/bin 安装: 1.解压 : tar -zxvf hadoop-2.7.7.tar. ...