• 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
    ", 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;
    
    }
    
  • 相关阅读:
    EBS Form菜单栏增加选项
    Oracle EBS 基础概念:弹性域-上下文字段
    EBS apps, applsys 的关系及密码更改
    设计模式-建造者模式
    微服务入门
    常见SQL编写和优化
    java 8 stream toMap问题
    mysql8.0.22在centos7.6下的简单安装
    mysql8的collate问题和修改
    springboot+security自定义登录-1-基础-自定义用户和登录界面
  • 原文地址:https://www.cnblogs.com/zjp-shadow/p/9767431.html
Copyright © 2020-2023  润新知