bzoj1997: [Hnoi2010]Planar
把回路的边想像成一个环,对于不在此上的边,有两种画法:在环内或环外
这就构成了2-sat二选一的要求。YY一下,容易想到构图。
然而状态很差写得很慢
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct node { int x,y,next; }a[2100000];int len,last[21000]; void ins(int x,int y) { len++; a[len].x=x;a[len].y=y; a[len].next=last[x];last[x]=len; } int z,dfn[21000],low[21000]; int top,sta[21000];bool v[21000]; int cnt,bel[21000]; void SCC(int x) { dfn[x]=low[x]=++z; sta[++top]=x;v[x]=true; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(dfn[y]==0) { SCC(y); low[x]=min(low[x],low[y]); } else if(v[y]==true) low[x]=min(low[x],dfn[y]); } if(low[x]==dfn[x]) { int k;cnt++; do { k=sta[top];top--; v[k]=false; bel[k]=cnt; }while(k!=x); } } struct edge{int x,y;}e[21000]; int pos[21000]; int main() { int T; scanf("%d",&T); while(T--) { int n,m,x; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d",&e[i].x,&e[i].y); for(int i=1;i<=n;i++) scanf("%d",&x),pos[x]=i; if(m>3*n-6){printf("NO\n");continue;} int tp=0; for(int i=1;i<=m;i++) { e[i].x=pos[e[i].x];e[i].y=pos[e[i].y]; if(e[i].x>e[i].y)swap(e[i].x,e[i].y); if(e[i].y-e[i].x==1||(e[i].y==n&&e[i].x==1))continue; e[++tp].x=e[i].x,e[tp].y=e[i].y; } m=tp; len=0;memset(last,0,sizeof(last)); for(int i=1;i<=m;i++) for(int j=i+1;j<=m;j++) if( (e[i].x<e[j].x&&e[j].x<e[i].y&&e[i].y<e[j].y) || (e[j].x<e[i].x&&e[i].x<e[j].y&&e[j].y<e[i].y)) { ins(i,j+m); ins(i+m,j); ins(j,i+m); ins(j+m,i); } z=top=cnt=0; memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(v,false,sizeof(v)); for(int i=1;i<=2*m;i++) if(dfn[i]==0)SCC(i); bool bk=true; for(int i=1;i<=m;i++) if(bel[i]==bel[i+m]){bk=false;break;} if(bk)printf("YES\n"); else printf("NO\n"); } return 0; }
pain and happy in the cruel world.