CF453C Little Pony and Summer Sun Celebration

如果一个点需要经过奇数次我们就称其为奇点,偶数次称其为偶点。

考虑不合法的情况,有任意两个奇点不连通(自己想想为什么)。

那么需要处理的部分就是包含奇点的唯一一个连通块。先随意撸出一棵生成树,然后正常地 dfs 下去。显然,叶子结点会成为奇点,非叶子结点会成为偶点。

当然这会存在不合法的情况,即我们需要改变一些结点的奇偶性。发现 dfs 到 \(u\) 结点的过程中我们可以进行这样一种操作,\(u\to v\to u(fa_v=u)\),它同时改变了 \(u\)\(v\) 的奇偶性。所以我们在处理完以 \(v\) 为根的子树后(即子树除了 \(v\) 都合法),如果 \(v\) 还不合法,我们就对 \(v\)\(v\) 的父亲 \(u\) 进行这个操作,使得 \(v\) 合法。

最后只剩下根结点,如果根结点不合法就去掉最后一步(不回到根结点)。

时间复杂度 \(O(n+m)\)~

code:

#include<bits/stdc++.h>
using namespace std;
#define N 100005
#define For(i,x,y)for(i=x;i<=(y);i++)
struct node
{
    bool used;
    int next,to;
}e[200005];
bool vis[N],rem[N];
int opt[400005],head[N],g,cnt;
int read()
{
    int A;
    bool K;
    char C;
    C=A=K=0;
    while(C<'0'||C>'9')K|=C=='-',C=getchar();
    while(C>'/'&&C<':')A=(A<<3)+(A<<1)+(C^48),C=getchar();
    return(K?-A:A);
}
inline void add(int u,int v)
{
    e[++g].to=v;
    e[g].next=head[u];
    head[u]=g;
}
void dfs(int u)
{
    int i,v;
    vis[u]=1;
    for(i=head[u];i;i=e[i].next)
    {
        v=e[i].to;
        if(!vis[v])dfs(v),e[i].used=1;
    }
}
bool work(int u,int fa)
{
    int i,v;
    bool bo=1,tmp;
    opt[++cnt]=u;
    for(i=head[u];i;i=e[i].next)
    if(e[i].used)
    {
        v=e[i].to;
        if(v==fa)continue;
        tmp=work(v,u);
        opt[++cnt]=u;
        bo^=1;
        if(!tmp)
        {
            opt[++cnt]=v;
            opt[++cnt]=u;
            bo^=1;
        }
    }
    return bo==rem[u];
}
void write(int X)
{
    if(X<0)putchar('-'),X=-X;
    if(X>9)write(X/10);
    putchar(X%10|48);
}
int main()
{
    int n,m,i,u,v;
    n=read(),m=read();
    For(i,1,m)
    {
        u=read(),v=read();
        add(u,v),add(v,u);
    }
    For(i,1,n)rem[i]=read();
    For(u,1,n)
    if(rem[u]&1)break;
    dfs(u);
    For(i,1,n)
    if(!vis[i]&&rem[i]&1)puts("-1"),exit(0);
    if(!work(u,0))cnt--;
    write(cnt);
    putchar('\n');
    For(i,1,cnt)write(opt[i]),putchar(' ');
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/May-2nd/p/13391894.html