[xsy2238]snake

题意:给定一条折线,问能否在不扭曲它的情况下让它完全通过一个小孔

这个条件就是:过折线上任意一点$x$存在一条直线把折线分成不与直线相交的两部分,换句话说存在(与折线只有一个交点$x$)的直线

结论是:若点$i$严格在点$1\cdots i$或点$i\cdots n$构成的凸包内,则无解,因为过点$i$的直线必然与折线在其他的某些位置相交

所以我们可以用set维护仅插入动态凸包,边插入边查询即可

实际上没有必要维护整个凸包,只维护原来的点还有它关于原点对称点的上凸壳就可以了

注意C++做布尔运算的短路机制==

#include<stdio.h>
#include<set>
using namespace std;
typedef long long ll;
struct point{
	int x,y;
	point(int a=0,int b=0){x=a;y=b;}
}p[100010];
point operator-(point a,point b){return point(a.x-b.x,a.y-b.y);}
ll operator*(point a,point b){return(ll)a.x*b.y-(ll)a.y*b.x;}
struct cmp{
	bool operator()(point a,point b){return a.x==b.x?a.y<b.y:a.x<b.x;}
};
struct conv{
	typedef set<point,cmp> st;
	typedef st::iterator si;
	st s;
	si it;
	si pre(si i){
		i--;
		return i;
	}
	si nex(si i){
		i++;
		return i;
	}
	point d[100010];
	int M,siz;
	void clear(){s.clear();siz=0;}
	bool insert(point p){
		it=s.lower_bound(p);
		if(it!=s.begin()&&it!=s.end()&&(p-*pre(it))*(*it-p)>=0)return 0;
		M=0;
		if(it!=s.begin()){
			it--;
			while(it!=s.begin()&&(*it-*pre(it))*(p-*it)>=0)d[++M]=*(it--);
		}
		it=s.lower_bound(p);
		if(it!=s.end()){
			while(nex(it)!=s.end()&&(*it-p)*(*nex(it)-*it)>=0)d[++M]=*(it++);
		}
		while(M)s.erase(d[M--]);
		s.insert(p);
		siz=s.size();
		return 1;
	}
}c1,c2;
int n;
void work(){
	int i;
	bool f1,f2;
	for(i=1;i<=n;i++)scanf("%d%d",&p[i].x,&p[i].y);
	c1.clear();
	c2.clear();
	for(i=1;i<=n;i++){
		f1=!c1.insert(p[i]);
		f2=!c2.insert(0-p[i]);
		if(f1&&f2){
			puts("Impossible");
			return;
		}
	}
	c1.clear();
	c2.clear();
	for(i=n;i>0;i--){
		f1=!c1.insert(p[i]);
		f2=!c2.insert(0-p[i]);
		if(f1&&f2){
			puts("Impossible");
			return;
		}
	}
	puts("Possible");
}
int main(){
	while(~scanf("%d",&n))work();
}
上一篇:oAuth2授权协议 & 微信授权登陆和绑定 & 多环境共用一个微信开发平台回调设置


下一篇:locations in main memory to be referenced by descriptive names rather than by numeric addresses