题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1997

平面图的一个定理:若边数大于(3*点数-6),则该图不是平面图。

然后就可以2-SAT了!

注意把输入读完再用定理continue!!!

注意边是元素,所以是i+m,而且数组也应开成M<<1!!!

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=405,M=605;
int T,n,m,hd[M<<1],xnt,x[M],y[M],mp[N];
int dfn[M<<1],low[M<<1],tim,sta[M<<1],top,col[M<<1],cnt;
bool ins[M<<1],flag;
struct Ed{
  int nxt,to;Ed(int n=0,int t=0):nxt(n),to(t) {}
}ed[(M*M)<<1];
bool check(int i,int j)
{
  int x1=mp[x[i]],y1=mp[y[i]],x2=mp[x[j]],y2=mp[y[j]];
  if(x1>y1)swap(x1,y1);
  if((x2>x1&&x2<y1&&(y2>y1||y2<x1))||(y2>x1&&y2<y1&&(x2>y1||x2<x1)))return true;
  return false;
}
void add(int i,int j)
{
  ed[++xnt]=Ed(hd[i],j+m);hd[i]=xnt;
  ed[++xnt]=Ed(hd[j],i+m);hd[j]=xnt;
  ed[++xnt]=Ed(hd[i+m],j);hd[i+m]=xnt;
  ed[++xnt]=Ed(hd[j+m],i);hd[j+m]=xnt;
}
void tarjan(int cr)
{
  dfn[cr]=low[cr]=++tim;
  sta[++top]=cr;ins[cr]=1;
  for(int i=hd[cr],v;i;i=ed[i].nxt)
    if(!dfn[v=ed[i].to])tarjan(v),low[cr]=min(low[cr],low[v]);
    else if(ins[v])low[cr]=min(low[cr],dfn[v]);
  if(dfn[cr]==low[cr])
    {
      cnt++;
      while(sta[top]!=cr)col[sta[top]]=cnt,ins[sta[top--]]=0;
      top--;col[cr]=cnt;ins[cr]=0;
    }
}
int main()
{
  scanf("%d",&T);
  while(T--)
    {
      scanf("%d%d",&n,&m);int z;
      for(int i=1;i<=m;i++)scanf("%d%d",&x[i],&y[i]);
      for(int i=1;i<=n;i++)
    scanf("%d",&z),mp[z]=i;
      if(m>3*n-6){printf("NO\n");continue;}//先把输入都读完再continue!!! 
      memset(hd,0,sizeof hd);xnt=0;
      for(int i=1;i<m;i++)
    for(int j=i+1;j<=m;j++)
      if(check(i,j))add(i,j);
      memset(dfn,0,sizeof dfn);tim=0;cnt=0;
      for(int i=1;i<=2*m;i++)if(!dfn[i])tarjan(i);
      flag=0;
      for(int i=1;i<=m;i++)
    if(col[i]==col[i+m]){flag=1;break;}
      if(flag)printf("NO\n");
      else printf("YES\n");
    }
  return 0;
}