Codeforces Round #453 (Div. 1) D. Weighting a Tree(构造)

题意

一个 \(n\) 个点 \(m\) 条边的无向连通图中每个点都有一个权值,现在要求给每条边定一个权值,满足每个点的权值等于所有相连的边权之和,权值可负。

题解

如果图是一棵树,那么方案就是唯一的,直接判一下就可以了,因为可以从叶子开始逐个确定回去。

否则先搞一棵 \(Dfs\) 树,先不管其他边,跑一遍,这时根节点可能还不满足条件(权值不为 \(0\) )。

这时考虑其他的边,一条非树边(返祖边)由于会形成一个环:

  • 如果是偶环,无论这条边权值如何变,都不会对根节点产生贡献;

  • 如果是奇环,当这条边权值改变 \(w\) 的时候,根据上面那个节点的奇偶性会对根产生 \(\pm 2w\) 的贡献。

    此时如果根节点需要的权值是奇数如何变化都是无法满足的,当为偶数的时候可以构造出一组合法方案。

总结

树上构造,常常从叶子往回考虑。

图上构造,可以先构造树,然后考虑非树边的贡献就行了。

代码

很好写qwq 但要注意开 long long

#include <bits/stdc++.h>

#define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << (x) << endl
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define Travel(i, u, v) for (int i = Head[u], v = to[i]; i; v = to[i = Next[i]]) 

using namespace std;

typedef long long ll;

template<typename T> inline bool chkmin(T &a, T b) {return b < a ? a = b, 1 : 0;}
template<typename T> inline bool chkmax(T &a, T b) {return b > a ? a = b, 1 : 0;}

inline int read() {
    int x(0), sgn(1); char ch(getchar());
    for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;
    for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
    return x * sgn;
}

void File() {
#ifdef zjp_shadow
	freopen ("D.in", "r", stdin);
	freopen ("D.out", "w", stdout);
#endif
}

const int N = 1e5 + 1e3, M = N << 1;

int n, m, need[N];

int Head[N], Next[M], to[M], e = 1;

inline void add_edge(int u, int v) {
	to[++ e] = v; Next[e] = Head[u]; Head[u] = e;
}

bitset<N> vis;
int dep[N], from[N], cid, cu, cv;

ll val[N];

void Dfs(int u, int fa) {
	ll cur = need[u];
	dep[u] = dep[fa] ^ 1; vis[u] = true;
	Travel(i, u, v) 
		if (!vis[v])
			from[v] = i ^ 1, Dfs(v, u), cur -= val[i >> 1];
		else if (!(dep[u] ^ dep[v]))
			cid = i >> 1, cu = u, cv = v;
	val[from[u] >> 1] = cur;
}

inline void Change(int u, int End, int w) {
	for (; u != End; u = to[from[u]])
		val[from[u] >> 1] += w, w *= -1;
}

inline void Out(bool flag) {
	if (!flag) return (void)puts("NO");
	puts("YES");
	For (i, 1, m)
		printf ("%lld\n", val[i]);
}

int main () {

	File();

	n = read(); m = read();
	For (i, 1, n)
		need[i] = read();
	For (i, 1, m) {
		int u = read(), v = read();
		add_edge(u, v); add_edge(v, u);
	}

	Dfs(1, 0);
	ll w = val[0];
	if (!w) return Out(true), 0;
	if ((w & 1) || !cid) return Out(false), 0;

	int opt = dep[cu] ? 1 : -1;
	Change(cu, 1, - opt * w); 
	Change(cv, cu, - opt * w >> 1); 
	val[cid] = opt * w >> 1;

	Out(true);

	return 0;

}
posted @ 2018-10-10 16:43  zjp_shadow  阅读(232)  评论(0编辑  收藏  举报