[HAOI2011]防线修建
题目描述
近来A国和B国的矛盾激化,为了预防不测,A国准备修建一条长长的防线,当然修建防线的话,肯定要把需要保护的城市修在防线内部了。可是A国上层现在还犹豫不决,到底该把哪些城市作为保护对象呢?又由于A国的经费有限,所以希望你能帮忙完成如下的一个任务:
给出你所有的A国城市坐标
A国上层经过讨论,考虑到经济问题,决定取消对i城市的保护,也就是说i城市不需要在防线内了
A国上层询问对于剩下要保护的城市,修建防线的总经费最少是多少
你需要对每次询问作出回答。注意单位1长度的防线花费为1。
A国的地形是这样的,形如下图,x轴是一条河流,相当于一条天然防线,不需要你再修建
A国总是有两个城市在河边,一个点是(0,0),一个点是(n,0),其余所有点的横坐标均大于0小于n,纵坐标均大于0。A国有一个不在(0,0)和(n,0)的首都。(0,0),(n,0)和首都这三个城市是一定需要保护的。
说明
数据范围:
30%的数据m<=1000,q<=1000
100%的数据m<=100000,q<=200000,n>1
所有点的坐标范围均在10000以内, 数据保证没有重点
题解
要动态维护一个凸包。还要维护删除操作?
删除麻烦,可以离线,把删除变成插入操作。
一切就简单又自然了。
插入一个点t,就要找到凸包上的第一个大于等于横坐标x的点p,和第一个小于x的点q。即后继前驱。
题目很善良,河边点不会删除,所以一定在凸包上,不会有什么边界的锅。
如果在凸包里面那么就直接返回,怎么判断?
如果q和p的斜率在t和p的斜率,t和q的斜率大小之间的话,那么这个点一定不在凸包上。画图可以理解。
反之就一定在凸包上。
然后开始弹出点。不断向右比较斜率,再不断向左比较斜率。
最后把t加入凸包。
删除点的时候,实时更新防线的长度。
不要忘了最后把p、q之间的连边删除。
找前驱后继再删除,可以用splay实现。
但是没有必要,set完全可以支持。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=+;
const double inf=19260817.0;
int n,m;
int cx,cy,far;
double now;
struct que{
int typ;
int id;
double ans;
}q[*N];
struct po{
int x,y;
bool friend operator<(po a,po b){
return a.x<b.x;
}
void op(){
cout<<" point "<<x<<" "<<y<<endl;
}
}a[N];
bool die[N];
set<po>s;
set<po>::iterator it1,it2,it3;
double dis(po a,po b){
return sqrt((double)(a.x-b.x)*(a.x-b.x)+(double)(a.y-b.y)*(a.y-b.y));
}
double slo(po a,po b){//(x1,y1) -> (x2,y2)
if(a.x==b.x){
return a.y>b.y?-inf:inf;
}
return ((double)a.y-(double)b.y)/((double)a.x-(double)b.x);
}
void upda(po lp){
//lp.op();
//cout<<" size "<<s.size()<<endl;
it2=s.lower_bound(lp);
it1=it2;it1--;
if(slo(*it1,lp)<=slo(*it1,*it2)&&slo(*it1,*it2)<=slo(lp,*it2)){
return;//has been protected;
}
now-=dis(*it1,*it2);
it3=it2;it3++;
while(it3!=s.end()&&slo(lp,*it2)<=slo(lp,*it3)){
now-=dis(*it2,*it3);
s.erase(it2);
it2=it3;
it3++;
}
now+=dis(lp,*it2);
it3=it1;it3--;
while(it1!=s.begin()&&slo(lp,*it1)>=slo(lp,*it3)){
now-=dis(*it1,*it3);
s.erase(it1);
it1=it3;
it3--;
}
now+=dis(lp,*it1);
s.insert(lp);
}
int main()
{
scanf("%d%d%d",&far,&cx,&cy);
scanf("%d",&n);int x,y;
for(int i=;i<=n;i++){
scanf("%d%d",&x,&y);
a[i].x=x,a[i].y=y;
}
scanf("%d",&m);
for(int i=;i<=m;i++){
scanf("%d",&q[i].typ);
if(q[i].typ==) scanf("%d",&q[i].id),die[q[i].id]=;
}
po st;st.x=,st.y=;s.insert(st);
po nd;nd.x=far,nd.y=;s.insert(nd);
po ca;ca.x=cx,ca.y=cy;s.insert(ca);
now=dis(st,ca)+dis(ca,nd);
for(int i=;i<=n;i++){
if(!die[i]){
upda(a[i]);
}
}
for(int i=m;i>=;i--){
if(q[i].typ==){
q[i].ans=now;
}
else{
upda(a[q[i].id]);
}
}
for(int i=;i<=m;i++){
if(q[i].typ==){
printf("%.2lf\n",q[i].ans);
}
}
return ;
}
总结:
现在我们有了一些斜率优化中,维护凸包的方法。
1.单调队列,适用于斜率有单调性,并且x要有单调性。才可以直接队头弹出,队尾插入。均摊O(1)
2.队列+二分。对于加入点的x有单调性,但是查询的斜率无单调性的时候,就要二分了。
二分到第一个斜率大于/小于查询斜率的点,作为决策点即可。除了队尾加入的时候,为了维护凸包所需,不会从队头弹出点。】
3.set(平衡树)维护。对于一般情况的凸包,可能加入的x在任何位置,查询什么凸包的周长,就必须用set了。
但是,对于斜率优化中,要查询一个第一个和后继/前驱比k大/小的点,因为set是按照x重载的运算符,不能直接lower_bound了。
所以,只能手写一棵splay,(就我所知)别无他法。
具体来说,一个splay树上的节点,按照x排序,而且必须还要记录和后继的斜率slope,和子树内所有后继斜率slope的最小值,便于直接二分。
[HAOI2011]防线修建的更多相关文章
- 【BZOJ 2300】 2300: [HAOI2011]防线修建 (动态凸包+set)
2300: [HAOI2011]防线修建 Description 近来A国和B国的矛盾激化,为了预防不测,A国准备修建一条长长的防线,当然修建防线的话,肯定要把需要保护的城市修在防线内部了.可是A国上 ...
- BZOJ 2300: [HAOI2011]防线修建( 动态凸包 )
离线然后倒着做就变成了支持加点的动态凸包...用平衡树维护上凸壳...时间复杂度O(NlogN) --------------------------------------------------- ...
- [luogu P2521] [HAOI2011]防线修建
[luogu P2521] [HAOI2011]防线修建 题目描述 近来A国和B国的矛盾激化,为了预防不测,A国准备修建一条长长的防线,当然修建防线的话,肯定要把需要保护的城市修在防线内部了.可是A国 ...
- P2521 [HAOI2011]防线修建
题目链接:P2521 [HAOI2011]防线修建 题意:给定点集 每次有两种操作: 1. 删除一个点 (除开(0, 0), (n, 0), 与指定首都(x, y)) 2. 询问上凸包长度 至于为什么 ...
- bzoj千题计划236:bzoj2300: [HAOI2011]防线修建
http://www.lydsy.com/JudgeOnline/problem.php?id=2300 维护动态凸包,人懒用的set 用叉积判断,不要用斜率 #include<set> ...
- 【BZOJ2300】[HAOI2011]防线修建 set维护凸包
[BZOJ2300][HAOI2011]防线修建 Description 近来A国和B国的矛盾激化,为了预防不测,A国准备修建一条长长的防线,当然修建防线的话,肯定要把需要保护的城市修在防线内部了.可 ...
- 【题解】P2521 [HAOI2011]防线修建(动态凸包)
[题解]P2521 [HAOI2011]防线修建(动态凸包) 凸包是易插入不好删除的东西,按照剧情所以我们时光倒流 然后问题就是维护凸包的周长,支持加入 本来很简单,但是计算几何就是一些小地方经验不足 ...
- BZOJ2300[HAOI2011]防线修建——非旋转treap+凸包(平衡树动态维护凸包)
题目描述 近来A国和B国的矛盾激化,为了预防不测,A国准备修建一条长长的防线,当然修建防线的话,肯定要把需要保护的城市修在防线内部了.可是A国上层现在还犹豫不决,到底该把哪些城市作为保护对象呢?又由于 ...
- LG2521 [HAOI2011]防线修建
题意 题目描述 近来A国和B国的矛盾激化,为了预防不测,A国准备修建一条长长的防线,当然修建防线的话,肯定要把需要保护的城市修在防线内部了.可是A国上层现在还犹豫不决,到底该把哪些城市作为保护对象呢? ...
随机推荐
- 【CentOS 7】scp示例
1,从远端拷贝到本地 /tmp路径 root@raspberrypi:/download/api_weather# scp root@123.207.xxx.xxx:/xxx/* /tmp 2,从本地 ...
- PHP字符编码转换库iconv的一个细节
先来看代码 <?php $charset = 'GBK'; $str = '中华人民共和国中华人民共和国中华人民共和国中华人民共和国'; ; $str2 = iconv('UTF-8', $ch ...
- Xcode中的Target
Xcode中的Target,主要包含下面几点知识: Target依赖 Build Phase Build Rule Target依赖 Target的依赖关系表示一个Target要构建成功,必先依赖于其 ...
- 奔跑吧DKY——团队Scrum冲刺阶段博客汇总
第一周:团队展示 团队选题 需求规格说明书 第二周:完善需求规格说明书.制定团队编码规范.通过团队项目数据库设计 奔跑吧DKY--团队Scrum冲刺阶段-Day 1-领航 奔跑吧DKY--团队Scru ...
- Python写一个根据日期计算是星期几的模块
import datetimedef get_week_day(date): week_day = { 0: '星期一', 1: '星期二', 2: '星期三', 3: '星期四', 4: '星期五' ...
- Teamwork(The sixth day of the team)
每日列会过后,我们的工作进度都有所进展了,好开心,但是还不是我们想要的,我们想做得更快,更好.
- JDBC连接数据库代码和步骤
JDBC连接数据库 创建一个以JDBC连接数据库的程序,包含7个步骤: 1.加载JDBC驱动程序 在连接数据库之前,首先要加载想要连接的数据库的驱动,这通过java.lang.Class类的静态方法 ...
- 51单片机,keilc51,如何使用data变量超过128怎么办
将堆栈指针SP指向128之后.如果你定义了数组.将数组定义为Idata.很难想象单个变量使用,你能用尽128个data类内存单元.如果真的用尽了,那只有将访问频率低的内存单元放到idata类去.总之, ...
- Internet History, Technology and Security (Week 2)
Week 2 History: The First Internet - NSFNet Welcome to week 2! This week, we'll be covering the hist ...
- Linux上两种网络连接方式
模式一:NAT方式好处:路由器更换,或者交换机更换,网络仍然可以使用,所用使用最多 准备工作: 查看VMware服务器启动情况,五个全开模式 vmnet8开启模式 1 配置VMware交换机的ip地址 ...