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;
}

 

posted @ 2018-08-29 18:48  AKCqhzdy  阅读(155)  评论(0编辑  收藏  举报