题目大意
判定一个具有哈密顿回路的图是否是平面图。
题解
我们把这个哈密顿回路的点按顺序拎出来分布在环上,继续观察这题的性质。(图在 csacademy 实在太难画了,摆)接下来我们只关心不是环边的环。
如果一条边与另一条边不在结点上相交,那么必定有一条要放到环外面,另一条放到环里面。拓展一下,如果三条边两两不在结点相交,那么一定不是平面图,总有一条边会与另外的边相交。
听上去是不是很像二分图?但是观察到
m
m
m 的范围实在是太大了,建图恐怕是不行的,毕竟还要有枚举的时间,于是我们直接观察平面图的性质。
在考场上我们没法严谨证明这些结论,但是平面图显然边数会有限制,我们可以去构造其偶环数量最多的情况,从而限制得到
m
⩽
3
n
−
6
m\leqslant 3n-6
m⩽3n−6。
得到了此结论后就可以随便做了,比如说二分图染色,2-SAT,并查集等等,这里用的是二分图染色,时间复杂度
O
(
T
n
2
)
\mathcal{O}(Tn^2)
O(Tn2)。
如何判断两条边是否相交?考虑将环上的点先铺成链,然后你会发现如果
[
l
1
,
r
1
]
[l_1,r_1]
[l1,r1] 与
[
l
2
,
r
2
]
[l_2,r_2]
[l2,r2] 相交且不包含,则
l
1
<
l
2
<
r
1
<
r
2
l_1<l_2<r_1<r_2
l1<l2<r1<r2(这里我们必须保证不在结点处相交),跟线段的判别是一致的。
十分需要注意的是哈密顿回路不一定按照
1
∼
n
1\sim n
1∼n 的顺序给你,如果你想更方便处理的话,你可以离散化一下。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e5+5;
const int inf=1e18;
struct edge{int x,y,vis;}a[N],b[N];
struct node{int to,nxt;}e[N];
int f[N],cnt,head[N],tot,col[N];
inline int read(){
char op=getchar();
int w=0,s=1;
while(op<'0'||op>'9'){
if(op=='-') s=-1;
op=getchar();
}
while(op>='0'&&op<='9'){
w=(w<<1)+(w<<3)+op-'0';
op=getchar();
}
return w*s;
}
bool cmp(edge x,edge y){
if(x.x==y.x) return x.y<y.y;
return x.x<y.x;
}
bool check(edge x,edge y){
if(x.x==y.x||x.y==y.y||x.y==y.x||x.x==y.y) return false;
if(x.x<y.x&&y.x<x.y&&x.y<y.y) return true;
return false;
}
void add(int x,int y){
e[++tot].to=y;
e[tot].nxt=head[x];
head[x]=tot;
}
bool dfs(int x,int k){
col[x]=k;
for(register int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
if(!col[y]){
col[y]=3-k;
int p=dfs(y,3-k);
if(!p) return false;
}else if(col[y]==k){
return false;
}else continue;
}
return true;
}
signed main(){
int T=read();
while(T--){
int n=read(),m=read();
cnt=0;
for(register int i=1;i<=m;i++){
a[i].x=read();
a[i].y=read();
a[i].vis=false;
}
for(register int i=1;i<=n;i++) f[i]=read();
if(m>3*n+6){
printf("NO\n");
continue;
}
memset(head,0,sizeof(head));
f[n+1]=f[1];
map<int,int> mp;
cnt=0;
for(register int i=1;i<=n;i++) mp[f[i]]=++cnt;//离散化一下
cnt=0;
for(register int i=1;i<=m;i++){
b[++cnt].x=mp[a[i].x];
b[cnt].y=mp[a[i].y];
if(b[cnt].x>b[cnt].y) swap(b[cnt].x,b[cnt].y);
}
sort(b+1,b+m+1,cmp);
bool c=false;
tot=0;
memset(col,0,sizeof(col));
for(register int i=1;i<=m;i++){
for(register int j=i+1;j<=m;j++){
if(check(b[i],b[j])){
add(i,j),add(j,i);
}
}
}
for(register int i=1;i<=m;i++){
if(!col[i]){
int k=dfs(i,1);
if(!k) c=true;
}
}
if(c) printf("NO\n");
else printf("YES\n");
}
}