zoukankan      html  css  js  c++  java
  • BZOJ.1997.[HNOI2010]Planar(2-SAT)

    题目链接

    存在一个环,说明什么?
    画了一下样例二,直接是个环;然后重新画了下样例一,可以画成一个环,非环上的边可以连在环内或环外
    这些非环上的边不能相交。然后就成了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;
    }
    
  • 相关阅读:
    标准化R包开发流程
    创建Rdemo项目
    rJava在ubuntu上的安装
    Linux初始root密码设置
    检查网卡错误
    统计学习方法-李航 第一章
    ubuntu16.04细节设置
    linux指令学习
    Python在ubuntu16.04上环境搭建
    kuberneets 1.17 设置 kube-reserved, system-reserved
  • 原文地址:https://www.cnblogs.com/SovietPower/p/8487571.html
Copyright © 2011-2022 走看看