1 2 3 4

CodeForces - 841D Leha and another game about graph

这是一个树上差分的问题;

 

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

 

想一个问题,在图上,选择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\n");
		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\n", cnn.size());
	for (int i = 0; i < cnn.size(); i++) {
		printf("%d\n", cnn[i]);
	}
	return 0;
}

  

posted @ 2019-11-30 16:23  Lesning  阅读(99)  评论(0编辑  收藏  举报