传送门:bzoj1035
题解
首先考虑面之间不存在包含关系的情况(图连通):
直接最小左转法平面图转对偶图。
除了 m n mn mn暴力求出每个军队所属平面的方法外,存在一种 s e t set set维护类似于扫描线的 O ( m log m ) O(m\log m) O(mlogm)做法:对于所有 l e . e d . x > l e . s t . x le.ed.x>le.st.x le.ed.x>le.st.x的边,在 s e t set set中维护所有经过当前 x x x坐标的边从上到下的相对位置关系(平面图中边不相交,所以必然存在绝对的相对位置关系)。扫到每个军队点时, l o w e r b o u n d lower_bound lowerbound找到它在它上面的最近的一条边的反向边所属平面(有向边左边是限制平面),即该点所属平面。
对于面之间存在包含关系的情况,同样可以用
s
e
t
set
set维护边信息,记录每个连通分量最上最左的一个点,将其与它上面最近的一条边连边,如下图:
内部的
a
a
a点向它上面最近的一条边(红边)的起点连线。
这样整个图就是连通的了,且平面图分割连通性保持不变。
代码十分毒瘤!要考虑的细节比较多。
p.s.
注意每条
l
e
.
e
d
.
x
>
l
e
.
s
t
.
x
le.ed.x>le.st.x
le.ed.x>le.st.x的边在扫描线中范围是左闭右开的,扫到某一
x
x
x值时要先删去所有
e
d
.
x
=
=
x
ed.x==x
ed.x==x的边。
s
e
t
set
set中比较函数写的时候需要注意(假设边
a
a
a在边
b
b
b上面)不能只判断
a
.
s
t
,
a
.
e
d
a.st,a.ed
a.st,a.ed是否都在
b
b
b的左侧,存在特例(如下图):
此时
a
.
e
d
a.ed
a.ed实际上是在
b
b
b的右侧的,但在
x
=
b
.
e
d
.
x
x=b.ed.x
x=b.ed.x之前,
a
a
a始终在
b
b
b上面,所以如果
b
.
s
t
,
b
.
e
d
b.st,b.ed
b.st,b.ed都在
a
a
a右侧也可以。
就是因为这个判断没想到 R E RE RE了5+次。
代码
#include<bits/stdc++.h>
#define mkp make_pair
#define pb push_back
#define ops(x) ((x&1)?(x+1):(x-1))
using namespace std;
typedef double db;
const int N=1e4+100,M=2e5+10;
const db eps=1e-8;
int n,m,cot,num,lim,sld[N];
int bel[N],tg[M],ans[N],tot;
map<int,int>mp[N<<1];
vector<int>nt[N];
bool vs[N],g[N][N];
struct P{
int x,y;
P(int x_=0,int y_=0):x(x_),y(y_){};
inline P operator +(const P&ky){return P(x+ky.x,y+ky.y);}
inline P operator -(const P&ky){return P(x-ky.x,y-ky.y);}
inline int operator ^(const P&ky){return x*ky.y-y*ky.x;}
inline P operator *(const db&ky){return P(x*ky,y*ky);}
inline P operator /(const db&ky){return P(x/ky,y/ky);}
}p[N];
struct Line{
P st,ed,dir;db ag;int x,y;
Line(){};
Line(P st_,P ed_,int x_,int y_)
{st=st_;ed=ed_;dir=ed-st;ag=atan2(dir.y,dir.x);x=x_;y=y_;}
}le[M];
int mst,aft;
struct afr{
int u,v,typ,id;
afr(){};
afr(int u_,int v_,int tp_){u=u_;v=v_;typ=tp_;}
bool operator <(const afr&ky)const{
if(p[u].x^p[ky.u].x) return p[u].x<p[ky.u].x;
return typ<ky.typ;
}
}af[M*3];
inline int dcmp(db x){if(fabs(x)<eps) return 0;return x>0?1:-1;}
void et(int x)
{
vs[x]=true;
if((p[x].y>p[mst].y)||(p[x].y==p[mst].y && p[x].x<p[mst].x)) mst=x;
for(int j,i=nt[x].size()-1;i>=0;--i) if(!vs[(j=le[nt[x][i]].y)]) et(j);
}
struct cmp{
inline bool operator()(const afr&a,const afr&b){
if(a.u==a.v) return ((p[b.v]-p[a.u])^(p[b.u]-p[a.u]))<0;
if(b.u==b.v) return ((p[a.v]-p[b.u])^(p[a.u]-p[b.u]))>0;
int aa=(p[b.v]-p[a.u])^(p[b.u]-p[a.u]),bb=(p[b.v]-p[a.v])^(p[b.u]-p[a.v]),
cc=(p[a.v]-p[b.u])^(p[a.u]-p[b.u]),dd=(p[a.v]-p[b.v])^(p[a.u]-p[b.v]);
return (aa<0 && bb<=0)||(aa<=0 && bb<0)||(cc>0 && dd>=0)||(cc>=0 && dd>0);
//不能只判(aa<0 && bb<=0)||(aa<=0 && bb<0)!
}
};
set<afr,cmp>T;
set<afr>::iterator si;
inline void merge()
{
int i,j;
for(i=1;i<=cot;++i) if(nt[i].size() && (!vs[i]))
{et((mst=i));af[++aft]=afr(mst,mst,2);}
for(i=1;i<=lim;++i) if(le[i].st.x<le[i].ed.x)
af[++aft]=afr(le[i].x,le[i].y,1),
af[++aft]=afr(le[i].y,le[i].x,0);
sort(af+1,af+aft+1);
for(i=1;i<=aft;++i)
switch(af[i].typ){
case 1: T.insert(af[i]);break;
case 0: T.erase(T.find(afr(af[i].v,af[i].u,1)));break;
case 2:
if((si=T.lower_bound(af[i]))!=T.begin()){
j=(--si)->u;
le[++m]=Line(p[j],p[af[i].u],j,af[i].u);nt[j].pb(m);
le[++m]=Line(p[af[i].u],p[j],af[i].u,j);nt[af[i].u].pb(m);
}
break;
}
}
inline void ins()
{
int i;T.clear();aft=0;
for(i=1;i<=n;++i) af[++aft]=afr(sld[i],sld[i],2);
for(i=1;i<=m;++i) if(le[i].st.x<le[i].ed.x)
af[++aft]=afr(le[i].x,le[i].y,1),af[aft].id=tg[ops(i)],
af[++aft]=afr(le[i].y,le[i].x,0);
sort(af+1,af+aft+1);
for(i=1;i<=aft;++i)
switch(af[i].typ){
case 1: T.insert(af[i]);break;
case 0: T.erase(T.find(afr(af[i].v,af[i].u,1)));break;
case 2:
si=--T.upper_bound(af[i]);
bel[af[i].u]=(si)->id;break;
}
}
inline int getid(int x,int y)
{
x+=10000;
if(mp[x].find(y)!=mp[x].end()) return mp[x][y];
p[++cot]=P(x-10000,y);return (mp[x][y]=cot);
}
inline bool nt_cmp(int x,int y)
{return dcmp(le[x].ag-le[y].ag)?le[x].ag<le[y].ag:(le[x].dir^le[y].dir)>0;}
int ot;
vector<int>::iterator it;
inline void dfs(int nw,int id)
{
int i,j,st=le[nw].x,pos=le[nw].y;tg[nw]=id;
int sum=p[st]^p[pos];
for(;st^pos;){
it=--upper_bound(nt[pos].begin(),nt[pos].end(),ops(nw),nt_cmp);
if(it==nt[pos].begin()) it=nt[pos].end();nw=*(--it);
j=le[nw].y;sum+=p[pos]^p[j];pos=j;tg[nw]=id;
}
if(sum<0) ot=id;
}
int main(){
int i,j,qx,qy,x,y;P a,b;
scanf("%d%d",&n,&m);
for(i=1;i<=n;++i)
{scanf("%d%d",&x,&y);sld[i]=getid(x,y);}
for(i=1;i<=m;++i){
scanf("%d%d",&a.x,&a.y);qx=getid(a.x,a.y);
scanf("%d%d",&b.x,&b.y);qy=getid(b.x,b.y);
j=(i<<1)-1;
le[j]=Line(a,b,qx,qy);le[j+1]=Line(b,a,qy,qx);
nt[qx].pb(j);nt[qy].pb(j+1);
}
m<<=1;lim=m;merge();
for(i=1;i<=cot;++i) sort(nt[i].begin(),nt[i].end(),nt_cmp);
for(i=1;i<=m;++i) if(!tg[i]) dfs(i,++num);
ins();
for(i=1;i<=m;i+=2) if((tg[i]^ot)&&(tg[i+1]^ot))
g[tg[i]][tg[i+1]]=g[tg[i+1]][tg[i]]=1;
for(i=1;i<=n;++i){
for(tot=0,j=1;j<=n;++j) if((i^j)&&g[bel[sld[i]]][bel[sld[j]]])
ans[++tot]=j;
printf("%d",tot);
for(j=1;j<=tot;++j) printf(" %d",ans[j]);
if(i<n) puts("");
}
}