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 ...
随机推荐
- mysql_8.0.12环境配置
1. 官网下载mysql_8.0.12免安装包,解压到你存放的地方: 2. 配置环境变量(把bin的文件夹弄进系统path里面): 3. 在解压的根路径中,查看是否含有my.ini文件,没有就新建一个 ...
- SLAM+语音机器人DIY系列:(二)ROS入门——5.编写简单的消息发布器和订阅器
摘要 ROS机器人操作系统在机器人应用领域很流行,依托代码开源和模块间协作等特性,给机器人开发者带来了很大的方便.我们的机器人“miiboo”中的大部分程序也采用ROS进行开发,所以本文就重点对ROS ...
- 使用 FFT 分析周期性数据
可以使用傅里叶变换来分析数据中的变化,例如一个时间段内的自然事件. 天文学家使用苏黎世太阳黑子相对数将几乎 300 年的太阳黑子的数量和大小制成表格.对大约 1700 至 2000 年间的苏黎世数绘图 ...
- [C#] C# 与 Nessus 交互,动态构建扫描任务计划
C# 与 Nessus 交互,动态构建扫描任务计划 目录 什么是 Nessus? 创建会话类 NessusSession 登录测试 创建操作类 NessusManager 操作测试 什么是 Nessu ...
- phpcms V9 二次开发------(获取点击数详解)
关于phpcms V9的点击数的使用应该有不少数是直接调用网上搜索到的代码,但是对于一些想要深入研究开发的人来说,看到网上的代码后更是不解,本人这几天看了看,了解了一些东西,在这里写出来分享一下,首先 ...
- React 16.x 新特性思维导图
React 16版本相对于以前的版本做了很大的改动,下面是我整理的React 16.x 新特性的思维导图文件,欢迎围观和指导:
- 各种raid对比
级别 最少单元 特征 冗余 性能 空间利用率 综合评价 RAID0 1 分片分散存入 否 读写2倍 100% 分散存储,任何一块坏掉数据则不完整 RAID1 2 相同数据存入2个磁盘 是 写不变,读快 ...
- iOS NFC
#import <CoreNFC/CoreNFC.h> @interface ViewController ()<NFCNDEFReaderSessionDelegate> @ ...
- 数据库MySQL和Redis实践
1.关于数据库设计的那些事 2.MySQL 3.Redis
- codeforces div2 220 解题
这套题我只写了a, b, c.. 对不起,是我太菜了. A:思路:就是直接简化为一个矩阵按照特定的步骤从一个顶角走到与之对应的对角线上的顶角.如图所示. 解释一下特定的步骤,就像马走日,象走田一样. ...