平面图总结
转对偶图
平面图的最小割对应着对偶图的最短路。
方法:
首先把每条边拆成双向边。
然后,把每个点的所有出边按极角进行排序。
每次:从任意一条未标记的边\((u,v)\)开始,把它标记,并找到v的出边中极角序在\((v,u)\)之后的第一条边。
直到找到一条被标记的边。
这时,我们就找到了一个面。通过这种方式,每条边恰好对应一个面。
一个面周围的所有边的反向边所对应的面,就是这个面的相邻面,在对偶图中建一条边。
最后,可以根据面积的正负性,找到那个无穷大的面。
这样,就完成了对偶图的建立。
代码:
int m,k=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d%d",&X[i],&Y[i]);
for(int i=0;i<m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
int za=addl(a,b,c);
int zb=addl(b,a,c);
tf[a].push_back(zb);
tf[b].push_back(za);
}
for(int i=1;i<=n;i++)
sort(ve[i].begin(),ve[i].end());
for(int i=1;i<=n;i++)
{
for(int j=0;j<ve[i].size();j++)
dy[i][ve[i][j].i]=j;
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<ve[i].size();j++)
fn[i][j]=dy[ve[i][j].v][tf[i][ve[i][j].i]];
}
for(int x=1;x<=n;x++)
{
for(int y=0;y<ve[x].size();y++)
{
if(bk[x][y])
continue;
int u=x,v=y,s=0;k+=1;
bool zd=false;SVe la;
while(!bk[u][v])
{
bk[u][v]=true;
ma[u][v]=k;
fflush(stdout);
int z=ve[u][v].v,t=(fn[u][v]+1)%ve[z].size();
bi[k].push_back(SBi(u,v));
SVe e=SPt(X[z],Y[z])-SPt(X[u],Y[u]);
if(s>0&&sgn(la*e)<0)
zd=true;
la=e;u=z;v=t;s+=1;
}
if(zd)out=k;
}
}
for(int i=1;i<=k;i++)
fr[i]=-1;
for(int i=1;i<=k;i++)
{
for(int j=0;j<bi[i].size();j++)
{
int u=bi[i][j].u,v=bi[i][j].v;
int z=ve[u][v].v,t=fn[u][v];
addb(i,ma[z][t],ve[u][v].c);
}
}
点定位
从该点,作一条平行于y轴的向上的射线。
求出这条射线与图中的边的交点的y坐标的最小值。
忽略图中平行于y轴的线段。若有多个,取对应的另一个点y坐标最小的那条边。
这条边所对应的面就是答案。
若有q组询问,暴力的时间复杂度为\(O(nq)\)。
若支持离线,可以通过扫描线优化至\(O((n+q)logn)\)。
用set维护所有交点,在全局变量中记录当前扫描到的x坐标。
在比较函数中使用这个变量。
代码:
struct SSe
{
int i,j,v;
double gety(int x)const
{
return ::gety(X[i],Y[i],X[v],Y[v],x);
}
SSe(){}
SSe(int I,int J,int V)
{
i=I;j=J;v=V;
}
};
bool operator<(const SSe &a,const SSe &b)
{
double ya=a.gety(WX),yb=b.gety(WX);
return ya<yb||(sgn(ya-yb)==0&&Y[a.i]<Y[b.i]);
}
void solve(int m)
{
multiset<SSe> se;
for(int i=0,a=0,b=0;i<m;i++)
{
while(b<n&&jd[b].x>xw[i].x)
{
int u=jd[b].i;
for(int j=0;j<ve[u].size();j++)
{
int v=ve[u][j].v;
if(X[v]>X[u])
se.erase(SSe(v,0,u));
}
b+=1;
}
WX=xw[i].x;
X[n+1+i]=xw[i].x;Y[n+1+i]=xw[i].y;
while(a<n&&jd[a].x>=xw[i].x)
{
int u=jd[a].i;
for(int j=0;j<ve[u].size();j++)
{
int v=ve[u][j].v;
if(X[v]<X[u]&&X[v]<=xw[i].x)
se.insert(SSe(u,j,v));
}
a+=1;
}
multiset<SSe>::iterator it=se.lower_bound(SSe(0,0,n+1+i));
if(it==se.end())
ans[xw[i].i]=out;
else
ans[xw[i].i]=ma[it->i][it->j];
}
}