CF70D(动态凸包)
给出q(<=1e5)个询问,每次在加上一个点,维护凸包,或者询问某个点是否在凸包内(在边上也算)。
听说可以用cdq做……但是并不会。我等蒟蒻只会用平衡树做。
首先,假设已经维护出了某个点按照极角排序的凸包,那么对于加入的一个点,我们首先要查询它是在凸包内还是凸包外(这个功能也可以用于题目中的查询)。O表示极角排序的原点,next表示极角排序的下一个点,pre则表示上一个点:
那么,如果p在凸包外,a( imes)b就是正数,若p在凸包内a( imes)b则是非正整数。
接着,我们要维护凸包。维护凸包依然要查询next和pre:
类似于gramham,不断通过删除next和pre维护凸包凸性。形象理解一下,可以看成p点伸出了两个筷子,不停尝试夹住凸包(凸包:喵喵喵?)
注意判断点是否在凸包内时,有个小坑点。O点必须选择在凸包内,既不能选择在凸包外也不能选择在凸包的边上。
#include <set>
#include <cmath>
#include <cstdio>
using namespace std;
typedef long long LL;
const LL maxn=1e5+5;
double ox=0, oy=0;
struct Point{
LL op, x, y; double angle;
Point (LL a=0, LL b=0):x(a), y(b){}
void getangle(){ angle=atan2(y-oy, x-ox); }
}p[maxn];
Point operator +(const Point &a, const Point &b){ return Point(a.x+b.x, a.y+b.y); }
Point operator -(const Point &a, const Point &b){ return Point(a.x-b.x, a.y-b.y); }
LL operator *(const Point &a, const Point &b){ return a.x*b.y-a.y*b.x; }
bool operator <(const Point &a, const Point &b){ //a是否在b的逆时针处
return a.angle<b.angle; }
LL q;
typedef multiset<Point>::iterator iter;
typedef Point Vector;
multiset<Point> s;
iter nxt(iter x){ return x==--s.end()?s.begin():++x; }
iter pre(iter x){ return x==s.begin()?--s.end():--x; }
bool in(iter x){
if (s.size()<3) return false;
return (*nxt(x)-*x)*(*pre(x)-*x)<=0; //叉积(是不是神仙操作)
}
void add(Point &x){
iter it=s.insert(x);
if (s.size()<=3) return;
if (in(it)){ s.erase(it); return; }
while (s.size()>3&&(*nxt(it)-*it)*(*nxt(nxt(it))-*nxt(it))<=0) //神仙操作*2
s.erase(nxt(it)); //注意加上=0以后,要判断size以免遇到两个点的情况
while (s.size()>3&&(*pre(it)-*it)*(*pre(pre(it))-*pre(it))>=0) //神仙操作*3
s.erase(pre(it));
}
bool query(Point &x){
iter it=s.insert(x); bool flag;
if (in(it)) flag=true; else flag=false;
s.erase(it); return flag;
}
int main(){
scanf("%lld", &q);
for (LL i=0; i<q; ++i)
scanf("%lld%lld%lld", &p[i].op, &p[i].x, &p[i].y);
Point t=p[0]+p[1]+p[2]; ox=(double)t.x/3; oy=(double)t.y/3;
//这样确定原点,保证原点不在凸包的边上
//若不这样:例子:A(-1, 0) B(1, 0) Q(4, 0)
for (LL i=0; i<q; ++i) p[i].getangle(); //确定极角
for (LL i=0; i<q; ++i){
if (p[i].op==1) add(p[i]);
else puts(query(p[i])?"YES":"NO");
}
return 0;
}