BZOJ1997: [Hnoi2010]Planar(并查集)

传送门

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

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

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

#include
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;jif(!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");
        }
    }
} 

你可能感兴趣的:(并查集)