zoukankan      html  css  js  c++  java
  • Atcoder:AGC004F Namori

    传送门
    先考虑树,树是一个二分图。
    看到是二分图并且每次是对两边的同色的点反色可以想到转化:让奇数层的点为黑,偶数为白,变成每次可以交换两个点的颜色。
    把黑看成 (-1),白看成 (1),那么求一个子树和,考虑每一条边的贡献可以得到 (ans=sum_{i=1}^{n} |sum_i|)
    如果根的 (sum) 不为 (0),那么肯定是无解的。
    对于基环树,先考虑奇环。
    断开奇环的一条边 ((u,v)),变成树,(u,v) 肯定是同一边的点。
    操作一次 ((u,v)) 相当于可以两边可以同时新增加白点/黑点,也就是可以把根的 (sum) 用这两个点来变成 (0),((sum) 必须为偶数)平均分配之后用树的做法即可。
    考虑偶环。
    断开偶环的一条边 ((u,v)),变成树,(u,v) 肯定不是同一边的点。
    操作一次 ((u,v)) 相当于是让左右的点走了一次捷径。
    设用的次数为 (x)
    如果一个点同时包含或不包含 (u,v) 两个点,那么 (sum) 一定不变。
    否则加上或者减去 (x)
    相当是是要求 (|x|+sum |sum_i-x| + sum |sum_i+x|)
    经典问题,排序之后取中位数即可。

    # include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int maxn(1e5 + 5);
    
    struct Edge {  int to, next;  };
    
    int n, m, first[maxn], cnt, sum[maxn], fa[maxn], dsu[maxn], deep[maxn], a, b, ans, val[maxn];
    Edge edge[maxn << 1];
    
    inline int Find(int x) {  return (dsu[x] ^ x) ? dsu[x] = Find(dsu[x]) : x;  }
    
    inline void Add(int u, int v) {
    	edge[cnt] = (Edge){v, first[u]}, first[u] = cnt++;
    	edge[cnt] = (Edge){u, first[v]}, first[v] = cnt++;
    }
    
    void Dfs(int u, int ff, int d) {
    	int e, v;
    	sum[u] = d;
    	for (e = first[u]; ~e; e = edge[e].next)
    		if ((v = edge[e].to) ^ ff) {
    			deep[v] = deep[u] + 1;
    			fa[v] = u, Dfs(v, u, -d);
    			sum[u] += sum[v];
    		}
    }
    
    int main() {
    	int i, u, v, len = 1;
    	memset(first, -1, sizeof(first));
    	scanf("%d%d", &n, &m);
    	if (n & 1) return puts("-1"), 0;
    	for (i = 1; i <= n; ++i) dsu[i] = i;
    	for (i = 1; i <= m; ++i) {
    		scanf("%d%d", &u, &v);
    		if (Find(u) ^ Find(v)) Add(u, v), dsu[Find(u)] = Find(v);
    		else a = u, b = v;
    	}
    	if (!a) {
    		Dfs(1, 0, 1);
    		if (sum[1]) return puts("-1"), 0;
    	}
    	else {
    		Dfs(a, 0, 1);
    		if (deep[b] & 1) {
    			if (sum[a]) return puts("-1"), 0;
    			for (i = b; i ^ a; i = fa[i]) val[++len] = sum[i], sum[i] = 0;
    			sort(val + 1, val + len + 1), v = val[(len + 1) >> 1];
    			for (i = 1; i <= len; ++i) ans += abs(val[i] - v);
    		}
    		else {
    			if (sum[a] & 1) return puts("-1"), 0;
    			v = sum[a] >> 1, ans = abs(v), sum[a] = 0;
    			for (i = b; i ^ a; i = fa[i]) sum[i] -= v;
    		}
    	}
    	for (i = 1; i <= n; ++i) ans += abs(sum[i]);
    	printf("%d
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    FrameBuffer系列 之 一点资源
    FrameBuffer系列 之 显示图片
    FrameBuffer系列 之 相关结构与结构体
    FrameBuffer系列 之 介绍
    FrameBuffer系列 之 简单编程
    程序员五大层次,你属于哪一层?
    提高编程效率的14件事
    GTK简单了解记录
    __read_mostly变量含义
    [系统启动]Printk与sched_clock_init的一点分析
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/10461698.html
Copyright © 2011-2022 走看看