BZOJ题目传送门
洛谷题目传送门
首先根据平面图的性质,如果 m>n∗3−6 ,那么这个图一定不是平面图。这样我们就可以把边数缩至 n 级别的了。
因为存在哈密顿回路,那么对于连接相同的两点的边,最多只能有两条(除了哈密顿回路的边),一条在环的里面,一条在环的外面。这样的限制满足2-SAT.
用手画几张图就可以发现,当两条边相交时,必然都在环的同一侧。记相交的边 i 连接的两点为 u 和 v ( u<v ),边 j 连接的两点为 x 和 y ( x<y ),可以发现 u<x<v<y 或 x<u<y<v 。因此当上述关系出现时,建边 <i,j xor 1> (选了i的这侧必须选j的另一侧,下同)、 <j,i xor 1> 以及它们的反边。缩点后判 i 和 i xor 1 是否在同一个联通块即可。
代码:
#include
#include
#include
#include
#define N 205
#define M 10005
#define K ((N*3-6)<<1)
using namespace std;
struct edge1{ int x,y; }edg[N<<1];
struct edge2{ int next,to; }ed[K*K<<2];
int n,m,t,tp,nd,s,p,k,h[K],c[N],e[M][2],hs[N];
int low[K],dfn[K],stk[K],num[K];
bool f[K],exst[N][N];
inline char readc(){
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
if (l==r) return EOF; return *l++;
}
inline int _read(){
int x=0; char ch=readc();
while (!isdigit(ch)) ch=readc();
while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=readc();
return x;
}
inline void addedge(int x,int y){
ed[++k].next=h[x],ed[k].to=y,h[x]=k;
}
void Tarjan(int x){
low[x]=dfn[x]=++p,stk[++tp]=x,f[x]=true;
for (int i=h[x],v=ed[i].to;i;i=ed[i].next,v=ed[i].to)
if (!dfn[v]) Tarjan(v),low[x]=min(low[x],low[v]);
else if (f[v]) low[x]=min(low[x],dfn[v]);
if (low[x]==dfn[x]){
f[x]=false,num[x]=++nd; int y;
do y=stk[tp--],f[y]=false,num[y]=nd; while (y!=x);
}
}
int main(){
t=_read();
while (t--){
memset(h,0,sizeof(h));
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
memset(num,0,sizeof(num));
memset(exst,false,sizeof(exst));
n=_read(),m=_read(); s=k=p=nd=0;
for (int i=1;i<=m;i++){
e[i][0]=_read(),e[i][1]=_read();
if (e[i][0]>e[i][1]) swap(e[i][0],e[i][1]);
}
for (int i=1;i<=n;i++){
hs[c[i]=_read()]=i;
if (i!=1) exst[min(c[i],c[i-1])][max(c[i],c[i-1])]=true;
}
if (m>n*3-6) { printf("NO\n"); continue; }
exst[min(c[1],c[n])][max(c[1],c[n])]=true;
for (int i=1;i<=m;i++){//要把在哈密顿回路上的边去掉
if (exst[e[i][0]][e[i][1]]) continue;
edg[s].x=e[i][0],edg[s].y=e[i][1],s+=2;
}
for (int i=0;i2;i+=2)
for (int j=i+2;j2){
int u=hs[edg[i].x],v=hs[edg[i].y],x=hs[edg[j].x],y=hs[edg[j].y];
if (u>v) swap(u,v); if (x>y) swap(x,y);
if ((ux&&vu&&y1),addedge(j,i^1);
addedge(j^1,i),addedge(i^1,j);
}
}
bool flag=false;
for (int i=0;i<(s<<1);i++) if (!dfn[i]) Tarjan(i);
for (int i=0;i<(s<<1);i+=2) if (num[i]==num[i^1]) { flag=true; break; }
if (flag) printf("NO\n"); else printf("YES\n");
}
return 0;
}