题解 CF840B

发布时间 2023-07-17 21:59:00作者: HQJ2007

构造题。

首先判断无解。每选一条边贡献两个度数,所以如果没有 \(-1\) 的点,且度数和为奇数,那么无解。

接下来考虑构造。我们考虑从图中扣下来一棵树(dfs 树),如果度数为奇数,令 \(-1\) 的点为根,否则随便选一个。

定义 \(tp_i\) 表示第 \(i\) 个节点是否需要与父亲连边,\(0\) 表示不用,\(1\) 表示用。然后对于当前点 \(u\),向所有满足 \(tp_v=1\) 的儿子连边,容易证明这是正确的。

因为,如果根为 \(-1\) 的点,那么根怎么连都行;否则,根据反证法,如果根还需要连边,而其他节点都已连好,那么总度数为奇数,矛盾。

复杂度 \(O(n)\)

code:

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5;
int n,m,d[N],tp[N],vis[N];
struct node{
  int v,id;
  node(int v=0,int id=0):v(v),id(id){}
};
vector<node>adj[N];
vector<int>ans;
void dfs(int u){
  int s=d[u];vis[u]=1;
  for(int i=0;i<adj[u].size();++i){
    int v=adj[u][i].v,id=adj[u][i].id;if(vis[v])continue;
    dfs(v);
    if(tp[v])s^=1,ans.push_back(id);
  }
  if(d[u]!=-1)tp[u]=s;
}
int main(){
  ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
  cin>>n>>m;
  int rt=1,f=0,s=0;
  for(int i=1;i<=n;++i){
    cin>>d[i];
    if(d[i]==-1)rt=f=i;
    else s^=d[i];
  }
  for(int i=1;i<=m;++i){
    int u,v;cin>>u>>v;
    adj[u].push_back(node(v,i));
    adj[v].push_back(node(u,i));
  }
  if(!f&&s)cout<<-1<<endl;
  else{
    dfs(rt);sort(ans.begin(),ans.end());
    cout<<ans.size()<<endl;
    for(int i=0;i<ans.size();++i)cout<<ans[i]<<endl;
  }
  return 0;
}