题目传送门
题目大意: 给出一张包含一个哈密顿回路的图,问这个图是不是平面图(即可以画在同一个平面上且边不相交)。
由于存在一个哈密顿回路(下面称作圆),所以每条边有三种连法:连在圆的内部,顺时针连在圆的外部,逆时针连在圆的外部,像这样:
但事实上可以发现,连在外部的话顺时针连和逆时针连其实是等价的,这个手玩一下数据就能明白(其实就是不管顺时针还是逆时针,会相交的还是会相交,不会相交的怎么都不会相交),那么每条边就只有两种连法。
假如对圆上的点按顺序重新编号,那么每条边可以看作一个区间,假如两个区间相交但不包含,那么这两个区间对应的边是不能同时在圆的同一侧的(即一个在内,一个在外才能不相交)。
诶,这似乎可以用 2 − S A T 2-SAT 2−SAT ?
边在内部还是外部对应 0 / 1 0/1 0/1 两种状态,分别设为点 i i i 和 i ′ i' i′,相交而不包含的边 a , b a,b a,b 之间 a a a 和 b ′ b' b′ 连边, b b b 和 a ′ a' a′ 连边,由于限制是相互的,所以要连无向边。然后看看有没有 i i i 和 i ′ i' i′ 能相互到达就好了。
由于连的是无向边而且只关心连通性,所以可以用并查集来搞。
而且如果直接枚举所有的边来建图,那么时间复杂度为 O ( m 2 ) O(m^2) O(m2),实测会TLE两个点,所以还需要稍微优化一下,也就是把所有边按左端点排序,当枚举的第 j j j 条边的左端点已经大于当前的第 i i i 条边的右端点,那么 j j j 之后的边都不可能与 i i i 相交了,直接break。
代码如下:
#include
#include
#include
using namespace std;
#define maxn 50010
int T,n,m;
struct section{
int x,y;}sec[maxn],a[maxn];
int id[maxn],t;
bool cmp(section x,section y){
return x.x<y.x;}
int f[maxn];
int findfa(int x){
return x==f[x]?x:f[x]=findfa(f[x]);}
int link(int x,int y){
x=findfa(x);y=findfa(y);if(x!=y)f[y]=x;}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&n,&m);
for(int i=1,x,y;i<=m;i++)scanf("%d %d",&sec[i].x,&sec[i].y);
for(int i=1,x;i<=n;i++)scanf("%d",&x),id[x]=i; t=0;
for(int i=1;i<=m;i++)
{
int x=id[sec[i].x],y=id[sec[i].y];if(x>y)swap(x,y);
if(x%n+1!=y&&y%n+1!=x)a[++t]=(section){
x,y};
}
sort(a+1,a+t+1,cmp);
for(int i=1;i<=2*t;i++)f[i]=i;
for(int i=1;i<=t;i++)
for(int j=i+1;j<=t;j++)
{
if(a[j].x>a[i].y)break;
if(a[i].x<a[j].x&&a[j].x<a[i].y&&a[j].y>a[i].y)
link(i,j+t),link(j,i+t);
}
bool ans=true;
for(int i=1;i<=t;i++)
if(findfa(i)==findfa(i+t)){
ans=false;break;}
if(ans)puts("YES"); else puts("NO");
}
}