码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ.1997.[HNOI2010]Planar(2-SAT)

时间:2018-03-01 13:28:16      阅读:156      评论:0      收藏:0      [点我收藏+]

标签:log   turn   define   code   min   getch   string   reg   efi   

题目链接

存在一个环,说明什么?
画了一下样例二,直接是个环;然后重新画了下样例一,可以画成一个环,非环上的边可以连在环内或环外
这些非环上的边不能相交。然后就成了POJ3207原题了,只是圆上排列顺序不同。
不过边数很多,必须利用平面图的性质: 平面图的边数小于等于3n-6,来将边数降到O(n)级别

当然这种并查集也能做。。
莫名跑的慢

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
//#define gc() getchar()
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
const int N=20005,M=4e5+5,MAXIN=2e6;

int n,m,A[N]/*规定一个数在圆上的位置*/,st[N],ed[N],Enum,H[N],nxt[M],to[M];
int sk[N],top,cnt,bel[N],id,dfn[N],low[N];
bool ins[N],isc[N];
char IN[MAXIN],*SS=IN,*TT=IN;

inline int read()
{
    int now=0;register char c=gc();
    for(;!isdigit(c);c=gc());
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now;
}
inline void AddEdge(int u,int v){
    to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
}
void Tarjan(int x)
{
    dfn[x]=low[x]=++id, sk[++top]=x, ins[x]=1;
    for(int v,i=H[x]; i; i=nxt[i])
        if(!dfn[v=to[i]]) Tarjan(v),low[x]=std::min(low[x],low[v]);
        else if(ins[v]) low[x]=std::min(low[x],dfn[v]);
    if(low[x]==dfn[x])
    {
        ++cnt;
        do{
            bel[sk[top]]=cnt, ins[sk[top--]]=0;
        }while(x!=sk[top+1]);
    }
}

int main()
{
    int t=read();
    while(t--)
    {
        n=read(),m=read();
        for(int i=1; i<=m; ++i) st[i]=read(),ed[i]=read();
        for(int i=1; i<=n; ++i) A[read()]=i;
        if(m>3*n-6) {puts("NO"); continue;}
        cnt=Enum=id=0, memset(H,0,sizeof H);
        memset(isc,0,sizeof isc), memset(dfn,0,sizeof dfn);
        for(int i=1; i<=m; ++i)
            if(A[st[i]]>A[ed[i]]) st[i]=A[st[i]],ed[i]=A[ed[i]],std::swap(st[i],ed[i]);
            else st[i]=A[st[i]],ed[i]=A[ed[i]];
        for(int i=1; i<=m; ++i)
            if(st[i]+1==ed[i]||(st[i]==1&&ed[i]==n)) isc[i]=isc[i+m]=1;
        for(int i=1; i<=m; ++i)
            if(!isc[i]) for(int j=1; j<=m; ++j)
                    if(!isc[j] && i!=j && st[j]<st[i]&&st[i]<ed[j]&&ed[j]<ed[i])
                        AddEdge(i,j+m),AddEdge(i+m,j),AddEdge(j,i+m),AddEdge(j+m,i);
        for(int i=1; i<=m<<1; ++i)//是枚举两个集合的边。。
            if(!isc[i] && !dfn[i]) Tarjan(i);
        bool f=1;
        for(int i=1; i<=m; ++i)
            if(!isc[i] && bel[i]==bel[i+m]) {f=0; break;}
        puts(f?"YES":"NO");
    }
    return 0;
}

BZOJ.1997.[HNOI2010]Planar(2-SAT)

标签:log   turn   define   code   min   getch   string   reg   efi   

原文地址:https://www.cnblogs.com/SovietPower/p/8487571.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!