Codeforces 841D Leha and another game about graph - 差分

时间:2021-11-03 21:13:11

Leha plays a computer game, where is on each level is given a connected graph with n vertices and m edges. Graph can contain multiple edges, but can not contain self loops. Each vertex has an integer di, which can be equal to 0, 1 or  - 1. To pass the level, he needs to find a «good» subset of edges of the graph or say, that it doesn't exist. Subset is called «good», if by by leaving only edges from this subset in the original graph, we obtain the following: for every vertex i, di =  - 1 or it's degree modulo 2 is equal to di. Leha wants to pass the game as soon as possible and ask you to help him. In case of multiple correct answers, print any of them.

Input

The first line contains two integers nm (1 ≤ n ≤ 3·105, n - 1 ≤ m ≤ 3·105) — number of vertices and edges.

The second line contains n integers d1, d2, ..., dn ( - 1 ≤ di ≤ 1) — numbers on the vertices.

Each of the next m lines contains two integers u and v (1 ≤ u, v ≤ n) — edges. It's guaranteed, that graph in the input is connected.

Output

Print  - 1 in a single line, if solution doesn't exist. Otherwise in the first line k — number of edges in a subset. In the next k lines indexes of edges. Edges are numerated in order as they are given in the input, starting from 1.

Examples
input
1 0
1
output
-1
input
4 5
0 0 0 -1
1 2
2 3
3 4
1 4
2 4
output
0
input
2 1
1 1
1 2
output
1
1
input
3 3
0 -1 1
1 2
2 3
1 3
output
1
2
Note

In the first sample we have single vertex without edges. It's degree is 0 and we can not get 1.


  题目大意 给定一个不包含自环的连通图,从中选出一些边使得特定的点满足入度的奇偶性。

  这里主要的问题是要处理要求入度为奇数的点(入度为偶数的点可以不连任何边)。然后仔细研究会发现,一条路径除了两端的点增加的度数为奇数,中间经过的点增加的度数都为偶数,这就很有用了。

  现在就考虑用一堆起点和终点(其实只用将要求度数为奇数的点任选两个配对,再选剩下中的两个,以此内推)都是要求入度为奇数的路径把它们的边集异或(因为当两条路径有一条公共的边后就会出事情,所以需要把这条边删掉)后得到的新的边集一定是合法的吗?(当然所有选择的点包含了所有要求入度为奇数的点)

  当要求度数为1的点的个数为奇数的时候就不一定了。因为总会存在一个点不满足要求。那么这时候就是没有限制的点的表演时间,就找一条路径把1个没有限制的点和这个点连接起来,路上的边的选择情况异或一下。

  至于如何快速搞定这个一堆边集取反的过程呢?

  首先考虑如果最终得到的图形上出现圈是否有意义?

  答案是没有意义,这一圈的边全都可以去掉,因为圈 = 首位相连的路径,这将意味着圈上任意点的度数加了2,这对奇偶性没有影响,是多余的,可以去掉。

  所以我们选择每条路径的起点和终点的时候都要求它们不同,所以最终得到的图形是森林。既然是在树上,就可以干很多事情了,比如树上差分。

  然后把对 边的取反信息 下放到子节点上(dfs树上),接着从任意一点进行一次dfs就好了。

Code

 /**
* Codeforces
* Problem#431D
* Accepted
* Time: 405ms
* Memory: 41000k
*/
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; int n, m;
int *gs;
int *rev;
vector<int> *g;
vector<int> *ig;
vector<int> c1, c2; inline void init() {
scanf("%d%d", &n, &m);
g = new vector<int>[n + ];
ig = new vector<int>[n + ];
gs = new int[(n + )];
rev = new int[(n + )];
memset(rev, , sizeof(int) * (n + ));
for(int i = ; i <= n; i++) {
scanf("%d", gs + i);
if(gs[i] == )
c1.push_back(i);
else if(gs[i] == -)
c2.push_back(i);
}
for(int i = , u, v; i <= m; i++) {
scanf("%d%d", &u, &v);
g[u].push_back(v);
g[v].push_back(u);
ig[u].push_back(i);
ig[v].push_back(i);
}
} vector<int> res;
boolean *vis;
void dfs(int node) {
vis[node] = true;
for(int i = ; i < (signed)g[node].size(); i++) {
int& e = g[node][i];
if(vis[e]) continue;
dfs(e);
if(rev[e]) res.push_back(ig[node][i]);
rev[node] ^= rev[e];
}
} inline void solve() {
int sc1 = (signed)c1.size(), sc2 = (signed)c2.size();
if((sc1 & ) && !sc2) {
puts("-1");
return;
}
vis = new boolean[(n + )];
memset(vis, false, sizeof(boolean) * (n + ));
for(int i = ; i < sc1; i += )
rev[c1[i]] = rev[c1[i - ]] = ;
if(sc1 & )
rev[c1[sc1 - ]] = rev[c2[]] = ;
dfs();
sc1 = (signed)res.size();
printf("%d\n", sc1);
for(int i = ; i < sc1; i++)
printf("%d\n", res[i]);
} int main() {
init();
solve();
return ;
}