BZOJ1997: [Hnoi2010]Planar(并查集)

传送门

题意:
给一个n个点大环,大环上有边,问这个图是不是平面图。 (n200,m10000)

题解:
二分图染色判断合法性很好想,但 m 这么大不可能m2建边。
听说有一个平面图定理:若图是平面图,那么 m3n6

那么直接剪枝 n2 判定就好了。

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    char ch=getchar();int i=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();}
    return i*f;
}
const int Maxn=2e2+50,Maxm=1e4+50;
int T,n,m,pos[Maxn],anc[Maxm<<1];
inline int getanc(int x){return (anc[x]==x)?x:(anc[x]=getanc(anc[x]));} 
struct edge{int x,y;}edge[Maxm];
inline bool judge_valid(int x,int y){
    int t1=pos[edge[x].x],t2=pos[edge[x].y],t3=pos[edge[y].x],t4=pos[edge[y].y];
    if(t1>t2)swap(t1,t2);
    return (t3>=t1&&t3<=t2&&t4>=t1&&t4<=t2)||((t3<=t1||t3>=t2)&&(t4<=t1||t4>=t2));
}
int main(){
    T=read();
    while(T--){
        n=read(),m=read();
        for(int i=1;i<=m;i++){
            edge[i].x=read();
            edge[i].y=read();
        }
        for(int i=1;i<=n;i++)pos[read()]=i;
        if(m>3*n-6)puts("NO");
        else{
            int bz=1;
            for(int i=1;i<=m;i++)anc[i]=i,anc[i+m]=i+m;
            for(int i=1;i<=m&&bz;i++){
                for(int j=1;j<i&&bz;j++){
                    if(!judge_valid(i,j)){
                        int t1=getanc(i),t2=getanc(j),t3=getanc(i+m),t4=getanc(j+m);
                        if(t1==t2||t3==t4){
                            puts("NO");bz=0;
                            break;
                        }
                        anc[t1]=t4;anc[t2]=t3;
                    }
                }
            }
            if(bz)puts("YES");
        }
    }
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值