构造题。
首先判断无解。每选一条边贡献两个度数,所以如果没有 \(-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;
}