图 - dfs

题目大意:给你一张无向图,你要么将其四染色,要么找到一个长度为奇数的环,删掉后图仍然是连通的。保证图连通。n<=1e5.
题解:考虑先求出一个dfs树,然后分层染0/1。然后考虑把那些两端颜色相同的非树边拿出来,若只考虑这些边存在奇环,那么显然把这个奇环删掉也还是连通的(因为都是非树边);否则按照非树边再做一次黑白染色,0变成12,1变成34就可以了。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
namespace INPUT_SPACE{
    const int BS=(1<<24)+5;char Buffer[BS],*HD,*TL;inline int gc() { if(HD==TL) TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);return (HD==TL)?EOF:*HD++; }
    inline int inn() { int x,ch;while((ch=gc())<'0'||ch>'9');x=ch^'0';while((ch=gc())>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0');return x; }
}using INPUT_SPACE::inn;
namespace OUTPUT_SPACE{
    char ss[100000*15],tt[20];int ssl,ttl; inline int PC(char c) { return ss[++ssl]=c; }
    inline int print(int x) { if(!x) ss[++ssl]='0';for(ttl=0;x;x/=10) tt[++ttl]=char(x%10+'0');for(;ttl;ttl--) ss[++ssl]=tt[ttl];return 0; }
    inline int Flush() { return fwrite(ss+1,sizeof(char),ssl,stdout),ssl=0,0; }
}using OUTPUT_SPACE::print;using OUTPUT_SPACE::PC;using OUTPUT_SPACE::Flush;
const int N=300010,M=300010;
struct edges{
    int to,pre,id;
}e[M<<1];int h[N],etop,vis[N],val[N],col[N],ban[M],ins[N],top,s[N],ans[N];
inline int add_edge(int u,int v,int id) { return e[++etop].to=v,e[etop].id=id,e[etop].pre=h[u],h[u]=etop; }
inline int get_dfs_tree(int x,int fa=0)
{
    vis[x]=1;
    for(int i=h[x],y;i;i=e[i].pre) if((y=e[i].to)^fa)
    {
        if(!vis[y]) val[y]=val[x]^1,get_dfs_tree(y,x),ban[e[i].id]=1;
        else if(val[y]^val[x]) ban[e[i].id]=1;
    }
    return 0;
}
inline int paint(int x,int fa=0)
{
    vis[x]=1,s[++top]=x,ins[x]=1;
    for(int i=h[x],y;i;i=e[i].pre)
        if(!ban[e[i].id]&&(y=e[i].to)!=fa)
        {
            if(!vis[y]) col[y]=col[x]^1,paint(y,x);
            else if(ins[y]&&col[x]==col[y])
            {
                int cnt=0;
                for(int j=top,z;(z=s[j])!=y;j--) ans[++cnt]=z;
                ans[++cnt]=y,PC('B'),PC(' '),print(cnt);
                rep(j,1,cnt) PC(' '),print(ans[j]);
                PC('\n'),Flush(),exit(0);
            }
        }
    return top--,ins[x]=0;
}
int main()
{
    int n=inn(),m=inn(),u,v;
    rep(i,1,m) u=inn(),v=inn(),add_edge(u,v,i),add_edge(v,u,i);
    get_dfs_tree(1);memset(vis,0,sizeof(int)*(n+1));
    rep(i,1,n) if(!vis[i]) top=0,col[i]=val[i]<<1,paint(i);
    PC('A');rep(i,1,n) PC(' '),print(col[i]+1);return PC('\n'),Flush(),0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值