大意:
给出一个
N
个点
N≤3∗105
,
N−1≤M≤3∗105
,
−1≤Ai≤1
解答:
若存在一个点的点权为-1,则选择一棵以该点为根的任意一棵生成树,从叶节点网上调整,若该点不满足条件则条件连向他父亲那条边的边权,那么除了根节点以外所有的点都能满足条件。而根节点权为-1,所以一定能得到一种满足题意的方案。
若不存在任何一个点权为-1,使用一棵dfs树来进行之前的调整,可以令所有的非树边的权值为0,若改变一条非树边的权值,则该非树边覆盖的路径上的所有边的权值都需要异或一,不会改变任何点所连接的边的异或和改变。故若无法满足根节点,则无解。
#include <bits/stdc++.h>
#define N 1000500
using namespace std;
struct Edge{int b,v,n;}e[N];
int h[N],d[N],cur[N],x[N],y[N],o[N],rt,n,m,tot,cnt;
bool flag,vis[N];
void link(int a,int b,int v) {
e[++cnt] = (Edge){b,v,h[a]}, h[a] = cnt;
}
inline int rd() {int r;scanf("%d",&r);return r;}
void dfs(int u,int f) {
vis[u] = 1;
for (int i=h[u];i;i=e[i].n) {
int v = e[i].b;
if (vis[v]) continue;
dfs(v, e[i].v);
}
if (d[u] != -1 && cur[u] != d[u]) {
if (!f) {
flag = 0;
return ;
}
if (x[f] == u) swap(x[f], y[f]);
cur[ x[f] ] ^= 1;
o[++tot] = f;
}
}
int main() {
rt = 1; flag = 1;
n = rd(), m = rd();
for (int i=1;i<=n;i++) d[i] = rd();
for (int i=1;i<=m;i++) {
int a = rd(), b = rd();
x[i] = a, y[i] = b;
link(a, b, i);
link(b, a, i);
}
for (int i=1;i<=n;i++) if (d[i] == -1) rt = i;
dfs(rt, 0);
if (!flag)
puts("-1");
else {
printf("%d\n",tot);
sort(o+1,o+tot+1);
for (int i=1;i<=tot;i++) printf("%d\n",o[i]);
}
return 0;
}