传送门
题解:
显然要做的事情就是确定平面划分然后上一遍扫描线点定位。
点定位的具体做法其实就是扫描线一下,找到自己上方第一条边,就能确定自己所在的平面了。
如果本身平面图上的点是连通的可以直接上最小左转法,但是题目里面第二个图那种就会出事。
解决方法是先搞出连通块,每个连通块最高的点用点定位的方法找到上方第一条线段,然后连到端点,这样不会破坏原来图的平面划分。然后上最小左转法。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define db double
#define cs const
namespace IO{
inline char gc(){
static cs int Rlen=1<<22|1;static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}template<typename T>T get(){
char c;bool f=false;while(!isdigit(c=gc()))f=c=='-';
T num=c^48;while(isdigit(c=gc()))num=((num+(num<<2))<<1)+(c^48);
return f?-num:num;
}inline int gi(){return get<int>();}
}using namespace IO;
using std::cerr;
using std::cout;
struct Pnt{
int x,y;Pnt(){}Pnt(int _x,int _y):x(_x),y(_y){}
friend Pnt operator+(cs Pnt &a,cs Pnt &b){return Pnt(a.x+b.x,a.y+b.y);}
friend Pnt operator-(cs Pnt &a,cs Pnt &b){return Pnt(a.x-b.x,a.y-b.y);}
friend int operator*(cs Pnt &a,cs Pnt &b){return a.x*b.y-b.x*a.y;}
int len()cs{return x*x+y*y;}db ang()cs{return atan2(y,x);}
};
struct cmpP{bool operator()(cs Pnt &a,cs Pnt &b){return a.x==b.x?a.y<b.y:a.x<b.x;}};
cs int N=8007,M=N<<1|7,K=607;
int n,m;
std::map<Pnt,int,cmpP> id;
Pnt p[N+K];int tot;
inline int get_id(cs Pnt &q){
int &cur=id[q];if(cur)return cur;
p[++tot]=q;return cur=tot;
}
int to[M],ec=1;db slope[M];
std::vector<int> E[N];
inline void adde(int u,int v){
E[u].push_back(++ec),to[ec]=v,slope[ec]=(p[v]-p[u]).ang();
E[v].push_back(++ec),to[ec]=u,slope[ec]=(p[u]-p[v]).ang();
}
inline bool cmp_e(int i,int j){
return slope[i]==slope[j]?to[i]<to[j]:slope[i]<slope[j];
}
int nxt[M],bel[M],bel_p[K],ct;
bool near[N][N];
namespace Area{
void get_area(){
for(int re i=1;i<=tot;++i)
std::sort(E[i].begin(),E[i].end(),cmp_e);
for(int re u=1;u<=tot;++u)
for(int re i=0;i<(int)E[u].size();++i){
int j=(i==0)?(E[u].size()-1):(i-1);
nxt[E[u][i]^1]=E[u][j];
}
for(int re i=2;i<=ec;++i){
if(bel[i])continue;bel[i]=++ct;
for(int re j=nxt[i];j!=i;bel[j]=ct,j=nxt[j]);
}
for(int re i=2;i<=ec;++i)near[bel[i]][bel[i^1]]=true;
}
}
namespace ScanLine{
struct atom{int a,b,t,id;};
inline bool operator<(cs atom &a,cs atom &b){
if(a.a==b.a&&a.t!=b.t)return a.t>b.t;
if(a.a==b.a)return (p[a.b]-p[a.a])*(p[b.b]-p[a.a])<0;
Pnt &p1=p[a.a],&p2=p[b.a];
return p1.x==p2.x?p1.y>p2.y:p1.x<p2.x;
}
struct cmp_atom{
bool operator()(cs atom &a,cs atom &b){
if(a.a==a.b)return (p[b.b]-p[a.a])*(p[b.a]-p[a.a])<0;
if(b.a==b.b)return (p[a.b]-p[b.a])*(p[a.a]-p[b.a])>0;
int t1=(p[b.b]-p[a.a])*(p[b.a]-p[a.a]),t2=(p[b.b]-p[a.b])*(p[b.a]-p[a.b]);
int t3=(p[a.b]-p[b.a])*(p[a.a]-p[b.a]),t4=(p[a.b]-p[b.b])*(p[a.a]-p[b.b]);
return (t1<0&&t2<=0)||(t2<0&&t1<=0)||(t3>0&&t4>=0)||(t4>0&&t3>=0);
}
};
std::set<atom,cmp_atom> S;
bool vis[N];int tp;
std::vector<atom> vec;
void dfs(int u){
vis[u]=true;if(p[u].y>p[tp].y)tp=u;
for(int re e:E[u])if(!vis[to[e]])dfs(to[e]);
}
void connect(){
vec.clear();S.clear();
for(int re i=1;i<=tot;++i)
if(E[i].size()&&!vis[i])
{dfs(tp=i),vec.push_back({tp,tp,1,0});}
for(int re i=1;i<=tot;++i)
for(int re e:E[i])
if(p[to[e]].x>p[i].x){
vec.push_back({i,to[e],0,0});
vec.push_back({to[e],i,2,0});
}
std::sort(vec.begin(),vec.end());
for(auto &t:vec){
switch(t.t){
case 0:S.insert(t);break;
case 2:S.erase(S.find({t.b,t.a,0,0}));break;
case 1:{
auto it=S.lower_bound(t);
if(it==S.begin())break;
adde((--it)->b,t.a);
}
}
}
}
void get_area(){
vec.clear();S.clear();
for(int re i=1;i<=n;++i)
vec.push_back({i,i,1,0});
for(int re i=1;i<=tot;++i)
for(int re e:E[i])
if(p[to[e]].x>p[i].x){
vec.push_back({i,to[e],0,e^1});
vec.push_back({to[e],i,2,e^1});
}
std::sort(vec.begin(),vec.end());
for(auto &t:vec){
switch(t.t){
case 0:S.insert(t);break;
case 2:S.erase(S.find({t.b,t.a,0,t.id}));break;
case 1:{
auto it=S.lower_bound(t);
bel_p[t.a]=bel[(--it)->id];
}
}
}
}
}
void Main(){n=gi(),m=gi();
for(int re i=1;i<=n;++i){
int x=gi(),y=gi();
get_id(Pnt(x,y));
}for(int re i=1;i<=m;++i){
int x1=gi(),y1=gi();
int x2=gi(),y2=gi();
int u=get_id(Pnt(x1,y1));
int v=get_id(Pnt(x2,y2));
adde(u,v);
}
ScanLine::connect();
Area::get_area();
ScanLine::get_area();
for(int re i=1;i<=n;++i){
std::vector<int> ans;
for(int j=1;j<=n;++j)
if(i!=j&&near[bel_p[i]][bel_p[j]])
ans.push_back(j);
cout<<ans.size();
for(int re t:ans)cout<<" "<<t;
cout<<"\n";
}
}
void file(){
#ifdef zxyoi
freopen("risk.in","r",stdin);
// freopen("risk.out","w",stdout);
#endif
}
signed main(){file();Main();return 0;}