【BZOJ】1997: [Hnoi2010]Planar - 2-SAT & 平面图结论

传送门:bzoj1997

读题…


题解

把哈密顿回路看成一个环,圆上相交的两条弧不能在同一侧(圆内/外)

O ( m 2 ) O(m^2) O(m2)过不了,但存在结论:

v ≥ 3 v\geq 3 v3的平面图 e ≤ 3 v − 6 e\leq 3v-6 e3v6

m > 3 n − 6 m>3n-6 m>3n6的判掉就过了


代码

#include<bits/stdc++.h>
using namespace std;
const int N=1200,M=8e5+10;

int tk,tp,n,m,a[N],b[N],pos[N];
int dfn,df[N],low[N],bel[N],cir,stk[N],top;
int head[N],to[M],nxt[M],tot;
 
void init(int n)
{
	int sz=(n+1)<<2;
    memset(head,0,sz);tot=0;
    memset(df,0,sz);memset(bel,0,sz);
	dfn=cir=top=0;
}

inline void lk(int u,int v)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;}

void tar(int x)
{
	int i,j,res;df[x]=low[x]=++dfn;stk[++top]=x;
	for(i=head[x];i;i=nxt[i]){
		j=to[i];
		if(!df[j]){
			tar(j);low[x]=min(low[x],low[j]);
		}else if(!bel[j]) low[x]=min(low[x],df[j]);
	}
	if(low[x]==df[x]){
		for(cir++;;){
			res=stk[top--];bel[res]=cir;
			if(res==x) break;
		}
	}
} 

int main(){
	int i,j,x,y,ix,iy;
	for(scanf("%d",&tk);tk;--tk){
		scanf("%d%d",&n,&m);tp=0;
		for(i=1;i<=m;++i) scanf("%d%d",&a[i],&b[i]);
		for(i=1;i<=n;++i) {scanf("%d",&j);pos[j]=i;}
		if(m>3*n-6) {puts("NO");continue;}
		for(i=1;i<=m;++i){
			a[i]=pos[a[i]];b[i]=pos[b[i]];
			if(a[i]>b[i]) swap(a[i],b[i]);
			if(a[i]+1<b[i]){a[++tp]=a[i];b[tp]=b[i];}
		}
		m=tp;tp=m<<1;init(tp);
		for(i=1;i<=m;++i){
			x=a[i];y=b[i];
			for(j=i+1;j<=m;++j){
				ix=a[j];iy=b[j];
				if((x<iy && x>ix && y>iy)||(x<ix && y>ix && y<iy))
				 lk(i,j+m),lk(j+m,i),lk(i+m,j),lk(j,i+m);
			}
		}
		for(i=1;i<=tp;++i) if(!df[i]) tar(i);
		for(i=1;i<=m;++i) if(bel[i]==bel[i+m]) break;
		puts(i<=m?"NO":"YES");
	} 
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值