题目链接

http://codeforces.com/gym/101630/attachments/download/6401/20172018-acmicpc-northeastern-european-regional-contest-neerc-17-en.pdf

题意

给出一些圆,这些圆圆心在x轴上方,且与x轴相切,任意时刻,不存在图上的圆相交,给出两种操作:增加一个圆;向图中发送一颗子弹,如果击中某个圆,输出该圆编号并且删掉这个圆。如果未击中,则输出-1。

题解

圆与x轴相切,且圆之间不相交,这说明,如果先把圆抽象成平行于x轴的线段的话,那么包含子弹横坐标的线段不超过log(N)log(N)log(N)个,这是一个很关键的条件。
如果我们能找出这些线段,那么我们就可以进行包含判定了。

下面关键的问题在于如何找出这些线段。
这里有一个骚操作,那就是使用线段树的方式。
我们先把圆一切两半,分别考虑,先考虑子弹打在右半边的情况,左半边的情况类似。
对于圆的右半边表示成线段就是[xr,xr+r][xr,xr+r][x_r,x_r+r],因为圆心不会重合,所以所有的xrxrx_r都不相同,这也正是我们要把圆切开的原因。
将线段存在线段树里,线段树xrxrx_r位置存放xr+rxr+rx_r+r,代表一个线段。并且要求线段树支持区间查询最大值的操作。
下面展示如何定位到所有的包含子弹横坐标xbxbx_b的线段。
我们采用分治的方法,初始待考虑区间为[0,xb][0,xb][0,xb](这样保证了线段的左端点<xb<xb<script type="math/tex" id="MathJax-Element-917">xbxbx_b(相当于判断线段的右端点>xb>xb>x_b),如果大于,说明在这个区间内有满足的线段,将区间进一步细分。
直到区间细分到长度为11<script type="math/tex" id="MathJax-Element-920">1</script>,停止,这就是一个满足条件的线段。

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
using namespace std;
const int maxn = 5e5+7;
int n;
int tp,x,y,len;
int segmx[maxn<<2],segmi[maxn<<2];
int al[maxn],cat = 0;
int mp[maxn];
#define pr(x) cout<<#x<<":"<<x<<endl
inline int getid(int x){return lower_bound(al,al+len,x) - al;
}
void updatemx(int rt,int l,int r,int pos,int x){if(l == r){segmx[rt] = x;return ;}int mid = (l+r)/2;if(pos <= mid) updatemx(rt*2,l,mid,pos,x);else updatemx(rt*2+1,mid+1,r,pos,x);segmx[rt] = max(segmx[rt*2],segmx[rt*2+1]);
}
void updatemi(int rt,int l,int r,int pos,int x){if(l == r){segmi[rt] = x;return ;}int mid = (l+r)/2;if(pos <= mid) updatemi(rt*2,l,mid,pos,x);else updatemi(rt*2+1,mid+1,r,pos,x);segmi[rt] = min(segmi[rt*2],segmi[rt*2+1]);
}int querymx(int rt,int l,int r,int ul,int ur){if(ul <= l && r <= ur)return segmx[rt];if(r < ul || l > ur) return -2e9;int mid = (l+r)/2;int ansl = querymx(rt*2,l,mid,ul,ur);int ansr = querymx(rt*2+1,mid+1,r,ul,ur);return max(ansl,ansr);
}int querymi(int rt,int l,int r,int ul,int ur){if(ul <= l && r <= ur)return segmi[rt];if(r < ul || l > ur) return 2e9;int mid = (l+r)/2;int ansl = querymi(rt*2,l,mid,ul,ur);int ansr = querymi(rt*2+1,mid+1,r,ul,ur);return min(ansl,ansr);
}
int tps[maxn],xs[maxn],ys[maxn];
int ans[maxn];
bool check(long long x,long long y,int id){long long dx = x - xs[id];long long dy = y - ys[id];if(dx*dx + dy*dy < y*y) return 1;return 0;
}
void dcmx(int l,int r,int id){int y = querymx(1,0,len-1,l,r);if(y <= xs[id]) return ;if(l == r){int x = al[l];y = y - x;if(check(x,y,id)) {ans[id] = mp[l];mp[l] = 0;updatemx(1,0,len-1,l,-2e9);updatemi(1,0,len-1,l,2e9);}return ;}int mid = (l+r)/2;dcmx(l,mid,id);dcmx(mid+1,r,id);}
void dcmi(int l,int r,int id){int y = querymi(1,0,len-1,l,r);if(y >= xs[id]) return ;if(l == r){int x = al[l];y = -y + x;if(check(x,y,id)) {ans[id] = mp[l];mp[l] = 0;updatemi(1,0,len-1,l,2e9);updatemx(1,0,len-1,l,-2e9);}return ;}int mid = (l+r)/2;dcmi(l,mid,id);dcmi(mid+1,r,id);}
int main(){scanf("%d",&n);for(int i = 1;i <= n;++i){scanf("%d%d%d",&tp,&x,&y);tps[i] = tp,xs[i] = x,ys[i] = y;if(tp == 1){al[cat++] = x;al[cat++] = x-y;al[cat++] = x+y;}else{al[cat++] = x;}}sort(al,al+cat);len = unique(al,al+cat) - al;memset(mp,0,sizeof(mp));for(int i = 0;i < maxn<<2;++i) segmx[i] = -2e9,segmi[i] = 2e9;for(int i = 1;i <= n;++i){int idx = getid(xs[i]);if(tps[i] == 1){mp[idx] = i;updatemx(1,0,len-1,getid(xs[i]),xs[i]+ys[i]);updatemi(1,0,len-1,getid(xs[i]),xs[i]-ys[i]);}else{dcmx(0,idx,i);dcmi(idx,len-1,i);}}for(int i = 1;i <= n;++i){if(tps[i] == 2){printf("%d\n",ans[i]?ans[i]:-1);}}return 0;
}

NEERC2017 Archery Tournament 线段树 新套路相关推荐

  1. CF1535D. Playoff Tournament(线段树维护)

    题目链接 题意: 前去洛谷自行观看吧链接放上了:https://www.luogu.com.cn/problem/CF1535D 分析: 正向并不能看出来什么,反向的话就是构成了一颗线段树,直接维护这 ...

  2. 李超线段树(Li-Chao Segment Tree)

    李超线段树 李超线段树是一种用于维护平面直角坐标系内线段关系的数据结构.它常被用来处理这样一种形式的问题:给定一个平面直角坐标系,支持动态插入一条线段,询问从某一个位置 (X,+∞)(X,+\inft ...

  3. [APIO2018] New Home 新家(线段树,二分答案,离散化)

    [APIO2018] New Home 新家 Solution 对于时间轴我们直接离散化+扫描线,维护每一个商店的加入和删除. 对于询问(x,t)(x,t)(x,t),不好直接回答,这里的关键一步是: ...

  4. [线段树]小喵喵的新家

    题目描述 小喵喵和小聪聪从小就是好朋友 ,他们经常在一起玩耍 .如今小喵已经厌倦了自己居住的环境,想请小聪聪为她建一个新家. 小喵喵天生多才多艺,对多种乐器颇有研究.对于生活中常见的图形,她对圆形很感 ...

  5. 线段树开新坑:kuangbin带你飞

    写在最前面的废话 这里I以前的题是暑假刚刚开始的时候在家写的,然后多校一波就荒废了 9月开头回家一波,重新填坑,= =,kuangbin带你飞的pdf,这才一半题,后面还有一波,蓝瘦,慢慢写吧,不写题 ...

  6. Luogu P1607 庙会班车【线段树】By cellur925

    题目传送门 据说可以用贪心做?算了算了...我都不会贪.... 开始想的是用线段树,先建出一颗空树,然后输进区间操作后就维护最大值,显然开始我忽视了班车的容量以及可以有多组奶牛坐在一起的信息. 我们肯 ...

  7. 主席树——多棵线段树的集合

    主席树: (不要管名字) 我们有的时候,会遇到很多种情况,对于每一种情况,都需要通过线段树的操作实现. 碰巧的是,相邻两种情况下的线段树的差异不大.(总体的差异次数是O(N)级别的,均摊就是O(常数) ...

  8. [非旋平衡树]fhq_treap概念及模板,例题:普通平衡树,文艺线段树

    文章目录 概念 全套模板 push_up模板 split拆树模板(按权值拆) split拆树模板(按个数拆) merge合并模板(地址版) merge合并模板(带返回根) 区间模板 insert插入模 ...

  9. HDU-4578 Transformation 线段树(两种方法)

    题目大意 多组数据(n,m同为0时结束),每组第一行一个 n 表有n个整数,一个 m 表有m条操作(1<=n,m<=1e5) 接下来 m 行,每行4个整数(1<=x<=y< ...

最新文章

  1. shader 3 rendering path
  2. c++中的 extern C
  3. 学长毕业日记 :本科毕业论文写成博士论文的神操作20170406
  4. oauth2 token为空拦截_feign之间传递oauth2-token的问题和解决
  5. python break跳出外层_失去循环标记的Python,我这样实现跳出外层循环
  6. 微信开源项目讲解使用公开课
  7. JavaScript验证正则表达式大全
  8. CTO视点 | 思科打造业界首个基于意图的开放性网络平台,释放无限机遇
  9. DirectUI的初步分析-转
  10. 面部捕捉技术_为什么选择魔神运动捕捉系统?
  11. jQuery基础-定位与修改
  12. 2021年中国水力发电装机量、发电量和竞争格局情况,总水电装机容量达391GW「图」
  13. 时间序列复杂性的度量—近似熵和样本熵
  14. 沧海云帆服务器哪里的,11月沧海云帆大区天涯合璧 合服服务器公告
  15. 花花公子跟风删除Facebook主页,区块链技术可打破互联网垄断
  16. mac 更新系统时间
  17. Apple开启双重认证过程
  18. 开水果店的水果怎么保鲜,新手开水果店水果保鲜方法
  19. 微信内置浏览器私有接口WeixinJSBridge的常用方法
  20. IT行业常用术语缩写

热门文章

  1. 未发现android设备,Brother iPrintScan 应用程序上出现错误信息“未发现支持设备”(Android™ 智能手机)。...
  2. .net mysql字符串截取_【MySQL】字符串截取之SUBSTRING_INDEX和【MySQL】字符串四则运算...
  3. python大鱼吃小鱼_python 游戏编程 大鱼吃小鱼
  4. 算法设计与分析——回溯法——批处理作业调度
  5. 数据结构 快速排序(详解)
  6. 如何将nodejs项目程序部署到阿里云服务器上
  7. 计算机等级delphi取消,计算机二级DELPHI控件:DELPHI过滤记录的实现方法
  8. IDEA如何在包下建立子包
  9. C++多态的基本语法与原理剖析
  10. MarkDown的介绍