BZOJ4814[Cqoi2017]小Q的草稿
来源:互联网 发布:linux lvs 配置 编辑:程序博客网 时间:2024/06/05 13:36
题目
BZOJ4814[Cqoi2017]小Q的草稿
题解
BZOJ这题通过率好像特低。。不造为啥。可能是数据不好造+容易写错。
我也是写了大半天迷迷糊糊的,找了篇题解思路才清晰起来。
首先要注意到这么一点,因为三角形不相交,那如果把三角形拆成三条线段,则不经过三角形区域即为关键点连线不与任何一条线段相交。
看到这题就应该很自然的联想到,枚举一个点然后极角排序然后维护一个啥。
很快我们发现,线段间的关系是不变的,大概意思就是,每条线段会遮盖一个极角区域,如果线段a在某个区域盖住了线段b(极角区域),线段b就不可能在某个区域盖住线段a。除非a消失,否则b一直被盖着。
画画图很好看出来的qw。不过这个实现特别蛋疼。
因为我写的计算几何题特别少。写了好久好久。最后还是懵逼。
我们需要发现这个事情,每个三角形只有一条边是有用的。起初我以为是一条或者两条,后来我发现。。点不可能在三角形内部,所以本质上还是只要一条,就是极角夹角(我不造是不是该这么叫。。可能看代码更好懂)最大的那两个点构成的那条边。
然后问题就简化了。只有线段和点。就打加线段标记,删除线段标记,然后那一堆按极角排序,用个set维护一下线段间的关系就好了。
一个小技巧就是,之前我一直被跨越x负半轴的线段所困扰,因为那两个极角、、、很蛋疼。但是某题解的作者用了一种非常棒的方法qwq。就是找出跟x轴负半轴的交点,然后拆成两条线段。这个方法真的解决了无数的困扰!!!!!!!在此特别向像我一样的计算几何萌新一定要记住这个方法!!!!因为枚举+扫描线+数据结构的题太多辣,这个思路也太妙啦。(dalao求不嘲讽萌新qwq)
个人觉得这道题考代码实现能力。比如说set里的小于号的定义要开一个全局变量。你得明白哪些set的操作要用小于号,否则会GG。
啊非常感谢某题解作者qwq,代码写的非常棒。
http://blog.csdn.net/u013849646/article/details/70197393
代码
//QWsin#include<set>#include<cmath>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int maxn=2000+10;const double eps=1e-9;const double PI=acos(-1.0);inline int dcmp(const double &x){ return x<-eps?-1:(x>eps ? 1:0);}struct point{ double x,y,ang; point(){x=y=0;} point (double x,double y):x(x),y(y){} inline void getang(){ang=atan2(y,x);} inline void input(){scanf("%lf%lf",&x,&y);} inline bool operator < (const point &rhs)const{ return dcmp(ang-rhs.ang)<0; }}p[maxn],pp[maxn],tr[maxn][5],tt[maxn][5];typedef point vc;inline vc operator - (const point &a,const point &b){return vc(a.x-b.x,a.y-b.y);}inline vc operator + (const point &a,const vc &b){return vc(a.x+b.x,a.y+b.y);}inline vc operator * (const vc &v,const double &k){return vc(v.x*k,v.y*k);}inline vc operator / (const vc &v,const double &k){return vc(v.x/k,v.y/k);}inline double dot(const vc &a,const vc &b){return a.x*b.x+a.y*b.y;}inline double cross(const vc &a,const vc &b){return a.x*b.y-a.y*b.x;}inline double getl(const vc &v){return (v.x*v.x+v.y*v.y);}inline double Ang(const point &a,const point &b){return (dot(a,b)/sqrt(getl(a))/sqrt(getl(b)));}inline vc jiao(const point &p1,const vc &v1,const point &p2,const vc &v2){ vc u=p1-p2; double t=cross(v2,u)/cross(v1,v2); return p1+v1*t; }int n,m;inline void init_data(){ cin>>n>>m; for(int i=1;i<=n;++i) p[i].input(); for(int i=1;i<=m;++i) for(int j=0;j<3;++j) tr[i][j].input();}const point O=point(0,0);vc base;//扫描线当前的位置 struct Line{ point x,y; double ang; int k,id; Line(){x=y=point();ang=0;k=0;} Line(point x,point y,double ang,int k,int id):x(x),y(y),ang(ang),k(k),id(id){} inline bool operator < (const Line &rhs)const{ double l1=getl(jiao(O,base,x,y-x)); double l2=getl(jiao(O,base,rhs.x,rhs.y-rhs.x)); return l1<l2; }}L[maxn*2];set<Line>st;set<Line>::iterator it,iit[maxn];inline int cmp(const Line &a,const Line &b){ return dcmp(a.ang-b.ang) < 0 || (dcmp(a.ang-b.ang)==0&&a.k > b.k); }int tot;inline void prework(int chose){ point P=p[chose]; for(int i=1,_=0;i<=n;++i) if(i!=chose) { pp[++_]=p[i]-P;pp[_].getang(); } sort(pp+1,pp+n); tot=0;int id_cnt=0; for(int i=1;i<=m;++i) { double mx=1e6; for(int j=0;j<3;++j) tt[i][j]=tr[i][j]-P; tt[i][3]=tt[i][0]; point u,v; for(int j=0;j<3;++j) { //因为点不会在三角形内部所以只有一条边有用(横跨最大的那条边) double ang=Ang(tt[i][j],tt[i][j+1]);//这里Ang没用acos,因为这个角度肯定小于180,减少acos调用次数 if(ang < mx){mx=ang;u=tt[i][j],v=tt[i][j+1];} } u.getang();v.getang(); if(u.ang > v.ang) swap(u,v); if(v.ang - u.ang < PI) { ++id_cnt; L[++tot]=Line(u,v,u.ang,1,id_cnt); L[++tot]=Line(u,v,v.ang,0,id_cnt); } else//过交界拆成两条线段,一个非常重要的技巧!!! { point tmp=jiao(u,v-u,O,point(-1,0)); tmp.ang=dcmp(u.ang)==1?PI:-PI; ++id_cnt; L[++tot]=Line(tmp,u,tmp.ang,1,id_cnt); L[++tot]=Line(u,tmp,u.ang,0,id_cnt); tmp.ang=dcmp(v.ang)==1?PI:-PI; ++id_cnt; L[++tot]=Line(v,tmp,v.ang,1,id_cnt); L[++tot]=Line(tmp,v,tmp.ang,0,id_cnt); } } sort(L+1,L+tot+1,cmp);}inline int solve(int id){ base=vc(0,0); if(id!=1)st.clear(); int j=1,ans=0; for(int i=1;i<n;++i) { while(j<=tot && (dcmp(L[j].ang-pp[i].ang) < 0 ||(dcmp(L[j].ang-pp[i].ang)==0&&L[j].k))){ base=L[j].x;//earse的时候也会用到base!! if(L[j].k==0) st.erase(iit[L[j].id]); else{ iit[L[j].id]=st.insert(L[j]).first; } ++j; } if(st.size()==0) {++ans;continue;} base=p[i]; it=st.begin(); double l1=getl(pp[i]); double l2=getl(jiao(O,pp[i],it->x,it->y - it->x)); ans+=(dcmp(l1 - l2)<0); }// printf("%d %d\n",id,st.size()); return ans;}int main(){ init_data(); int ans=0; for(int i=1;i<=n;++i) { prework(i); ans+=solve(i); } cout<<ans/2; return 0;}
- 【CQOI2017】 bzoj4814 小Q的草稿
- BZOJ4814[Cqoi2017]小Q的草稿
- bzoj 4814 [Cqoi2017]小Q的草稿
- 4814: [Cqoi2017]小Q的草稿
- [几何] BZOJ 4814 [Cqoi2017]小Q的草稿
- 【CQOI2017】小Q的棋盘
- CQOI2017 小Q的棋盘
- 【数论】[CQOI2017]小 Q 的表格
- bzoj 4813 [Cqoi2017]小Q的棋盘
- 【CQOI2017】bzoj4813 小Q的棋盘
- BZOJ 4813 [Cqoi2017]小Q的棋盘
- bzoj4815 [Cqoi2017]小Q的表格
- 【CQOI2017】bzoj4815 小Q的表格
- BZOJ4813: [Cqoi2017]小Q的棋盘
- BZOJ4813 [Cqoi2017]小Q的棋盘
- bzoj 4815: [Cqoi2017]小Q的表格
- 【BZOJ4815】 [Cqoi2017]小Q的表格
- 4813: [Cqoi2017]小Q的棋盘
- Tolua使用笔记六:在lua中操作C#的委托事件与在lua中对Unity的GameObject的操作
- 171. Excel Sheet Column Number
- 蓝桥杯--基础练习:十六进制转十进制
- intellij idea tomcat 启动报错not found for the web module
- Android案例:SQLite数据库学习
- BZOJ4814[Cqoi2017]小Q的草稿
- you-get的使用及安装说明
- 常见的分页实现方式(Java)
- ElasticSearch学习笔记 安装 配置
- Lucene教程--维护索引、查询对象和相关度排序
- 八.javaweb之解决中文乱码问题
- 1
- Hadoop源码解析之动态调整MapTask的内存资源大小
- 2017经典面试题必杀技——你值得收藏