BZOJ传送门
洛谷传送门
解析:
首先记住一个结论:对于任意平面图都有 ∣ E ∣ ≤ 3 ∣ V ∣ − 6 |E|\leq3|V|-6 ∣E∣≤3∣V∣−6
证明一下:只考虑极大平面图(即点数一定时,边数达到最大的平面图)。其他的情况边数都小于同顶点数的极大平面图。
首先,极大平面图的每个平面由3条边围成,不然总是能够在这个形状中继续连一条对角线加边。
令
r
r
r为该平面图面数,
m
m
m为边数,
n
n
n为点数。
由于是极大平面图,所以有
3
r
=
2
m
3r=2m
3r=2m,即每条边被两个平面共享,每个平面由三条边围成。
由平面图的欧拉公式 n − m + r = 2 n-m+r=2 n−m+r=2(直接将拓扑学的立体图形映射到平面上即可得到),那么极大平面图有 m = 3 n − 6 m=3n-6 m=3n−6。其他情况 m ′ < m = 3 n − 6 m'<m=3n-6 m′<m=3n−6
所以对于任意平面图,总是有 m ≤ 3 n − 6 m\le 3n-6 m≤3n−6。
那么我们就排除那些不符合题意的图,将边的规模优化到 O ( n ) O(n) O(n)了。
由于这道题的图都有哈密尔顿回路,所以可以乱搞一下。
将哈密尔顿回路看作一个圈,剩下的边要么是圆上的弦,要么就在圆外。
显然如果两条边有交点,它们必须处于不同的两侧,
所以我们可以将它们连边,随后染色判断一下是否是二分图就行了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return num;
}
cs int N=205,M=10004;
vector<int> edge[N*3+8];
int a[M],b[M];
int H[N];
inline void addedge(int u,int v){
edge[u].push_back(v);
edge[v].push_back(u);
}
int col[N*3+8];
int T,n,m;
inline void clear(){
memset(col,-1,sizeof col);
for(int re i=1;i<=m;++i)edge[i].clear();
}
inline bool dye(int u){
for(int re e=0;e<edge[u].size();++e){
int re v=edge[u][e];
if(col[v]==col[u])return false;
if(col[v]==-1){
col[v]=col[u]^1;
if(!dye(v))return false;
}
}
return true;
}
signed main(){
T=getint();
while(T--){
n=getint();
m=getint();
for(int re i=1;i<=m;++i){
a[i]=getint();
b[i]=getint();
}
for(int re i=1;i<=n;++i)H[getint()]=i;
if(m>3*n-6){
puts("NO");
continue;
}
clear();
for(int re i=1;i<=m;++i)
for(int re j=i+1;j<=m;++j){
int u1=H[a[i]],v1=H[b[i]],u2=H[a[j]],v2=H[b[j]];
if(u1>v1)swap(u1,v1);
if(u2>v2)swap(u2,v2);
if((u1<u2&&u2<v1&&v1<v2)||(u2<u1&&u1<v2&&v2<v1)){
addedge(i,j);
}
}
bool flag=true;
for(int re i=1;i<=m;++i){
if(~col[i])continue;
col[i]=0;
if(!dye(i)){
flag=false;
break;
}
}
puts(flag?"YES":"NO");
}
return 0;
}