这是一个树上差分的问题;
题目大意 给定一个不包含自环的连通图,从中选出一些边使得特定的点满足入度的奇偶性。
想一个问题,在图上,选择ab两个顶点,记录下他们的路径,经过的顶点度数+=2,对奇偶没有影响。
二两端的顶点度数++;所以问题关键,每个标记1 的点,找两个让他们添加一条边,
那么要如何操作呢,这里有一种异或的方法,
举例
list[3] = 1; list[6] = 1;
for(int i=0;i<10;i++) list[i] ^= list[i-1];
这样之后,3,4,5都被标记为1,[3,6)区间被标记成功,类似前缀和(树上差分是树的前缀和,记录边(区间));
具体看代码把
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define maxn 300000+10
using namespace std;
int list[maxn];
struct Node {
int p;
int len;
Node(int a, int b) :p(a), len(b) {}
};
vector<Node>G[maxn];
void insert(int be, int en, int len) {
G[be].push_back(Node(en, len));
}
vector<int>ins1, ins2,cnn;
int vis[maxn];
int ans[maxn];
int dfs(int x) {
vis[x] = 1;
for (int i = 0; i < G[x].size(); i++) {
int p = G[x][i].p;
if (vis[p]) continue;
dfs(p);
if (ans[p]) cnn.push_back(G[x][i].len);
ans[x] ^= ans[p];
}
return 0;
}
int main() {
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", &list[i]);
if (list[i] == 1) ins1.push_back(i);
if (list[i] == -1) ins2.push_back(i);
}
int be, en;
for (int i = 1; i <= m; i++) {
scanf("%d %d", &be, &en);
int len = i;
insert(be, en, len);
insert(en, be, len);
}
if (ins1.size() % 2 == 1 && ins2.size() == 0) {
printf("-1
");
return 0;
}
for (int i = 0; i < ins1.size(); i++) {
ans[ins1[i]] = 1;
}
if (ins1.size() % 2 == 1) ans[ins2[0]] = 1;
dfs(1);
printf("%d
", cnn.size());
for (int i = 0; i < cnn.size(); i++) {
printf("%d
", cnn[i]);
}
return 0;
}