AtCoder AGC004F Namori (图论)
题目链接
https://atcoder.jp/contests/agc004/tasks/agc004_f
题解
神仙题。。
首先考虑树的情况,树是二分图,因此假设我们对二分图进行黑白染色,那么操作就变成了,每次选择两个不同色的点来取反。然后再把黑色视作标记,那么问题就变成了,初始一些点上有标记,每次可以把标记沿着边移动到一个没标记的点,要把标记全部移动到和原来不同的位置上,求最小代价!
然后这个问题的做法就是,首先如果两种颜色个数不同就无解,否则考虑一个下界,对于每一条边而言,它至少要运送标记的次数等于其一端子树内黑白点个数差的绝对值。对所有的边求和就是答案的下界,而我们也能构造出来一种达到这个下界的方案,构造详见官方题解。
然后考虑基环树。当环是奇环和偶环时,其作用不同,因此需要分类讨论。
当环是偶环时,非树边的作用是多了一条运送标记的边。假设这条边运送了\(x\)个标记(可正可负),那么其所影响的是环上的点,需要最小化的是一个\(\sum |x-a_i|\)的形式,直接取中位数即可。
当环是奇环时,非树边的作用是可以给两个端点的标记同时\(+1\)或\(-1\). 显然\(+1\)和\(-1\)都出现是不优的,由于操作可逆可以假设是\(+1\) (否则交换初始状态和终止状态)。在这种情况下,若两种颜色个数奇偶性不同就无解,否则执行这种操作的次数\(x\)是确定的(因为初始和终止时两种颜色点数确定)。那么就可以认为给这两个端点分别加了\(x\)个标记,然后再执行树的算法即可。
时间复杂度\(O(N)\)或\(O(N\log N)\).
代码
#include<bits/stdc++.h>
#define llong long long
using namespace std;const int N = 1e5;
struct Edge
{int nxt,v;
} e[(N<<1)+3];
int fe[N+3];
int fa[N+3];
bool vis[N+3];
int dep[N+3];
int a[N+3];
int s[N+3];
vector<int> vec;
int n,m,en,au,av,sum;
llong ans;int absl(int x) {return x<0?-x:x;}void addedge(int u,int v)
{en++; e[en].v = v;e[en].nxt = fe[u]; fe[u] = en;
}void dfs(int u,int prv)
{a[u] = dep[u]&1?-1:1; sum += a[u]; s[u] = a[u];vis[u] = true;for(int i=fe[u]; i; i=e[i].nxt){int v = e[i].v;if(v==prv) continue;if(vis[v]){au = u,av = v;}else{dep[v] = dep[u]+1;fa[v] = u;dfs(v,u);s[u] += s[v];}}
}void dfs2(int u,int prv)
{s[u] = a[u];vis[u] = true;for(int i=fe[u]; i; i=e[i].nxt){int v = e[i].v;if(v==prv) continue;if(vis[v]){au = u,av = v;}else{dep[v] = dep[u]+1;dfs2(v,u);s[u] += s[v];}}
}int main()
{scanf("%d%d",&n,&m);for(int i=1; i<=m; i++){int u,v; scanf("%d%d",&u,&v);addedge(u,v); addedge(v,u);}sum = 0; dep[1] = 0; dfs(1,0);if(m==n-1){if(sum) {puts("-1");}else{ans = 0ll;for(int i=1; i<=n; i++){ans += absl(s[i]);}printf("%lld\n",ans);}}else if(m==n){if(dep[au]>dep[av]) swap(au,av);if((dep[au]^dep[av])&1){if(sum) {puts("-1");}else{vec.clear();int v = av;while(dep[v]>dep[au]){vec.push_back(-s[v]);v = fa[v];}sort(vec.begin(),vec.end());int x = vec[vec.size()>>1];a[au] -= x; a[av] += x;for(int i=1; i<=n; i++) vis[i] = 0;dfs2(1,0);ans = absl(x);for(int i=1; i<=n; i++){ans += absl(s[i]);}printf("%lld\n",ans);}}else{if(absl(sum)&1) {puts("-1");}else{if(sum>0){for(int i=1; i<=n; i++) s[i] = -s[i],a[i] = -a[i];sum = -sum;}int x = (-sum)>>1;a[au] += x; a[av] += x;for(int i=1; i<=n; i++) vis[i] = 0;dfs2(1,0);ans = x;for(int i=1; i<=n; i++){ans += absl(s[i]);}printf("%lld\n",ans);}}}for(int i=1; i<=n; i++) fe[i] = vis[i] = fa[i] = 0;for(int i=1; i<=en; i++) e[i].v = e[i].nxt = 0;en = 0;return 0;
}
AtCoder AGC004F Namori (图论)相关推荐
- [agc004f]Namori
前言 这题好牛逼啊. 题目大意 给你一颗全白的树或环套树. 你每次可以选择一条连接两个同色点的边,将两个端点反色. 问变成全黑的最小步数,要求判断无解. 树的做法 树是一个二分图,看起来很棒的样子. ...
- win10桌面图标有小白标_白标移动应用程序,带有react native和babel
win10桌面图标有小白标 In my previous article, I described a solution for white labelling web applications wh ...
- AtCoder AGC043C Giant Graph (图论、SG函数、FWT)
题目链接 https://atcoder.jp/contests/agc043/tasks/agc043_c 题解 场上感觉没啥思路就放弃了,场下想了十几分钟发现是水题,血亏...(只能怪自己计数水平 ...
- AtCoder AGC033F Adding Edges (图论)
------------恢复内容开始------------ 题目链接 https://atcoder.jp/contests/agc033/tasks/agc033_f 题解 又被神仙题搞自闭了-- ...
- AtCoder AGC031F Walk on Graph (图论、数论)
题目链接 https://atcoder.jp/contests/agc031/tasks/agc031_f 题解 这题真是太神仙了-- 首先我们转化一下问题,倒着来做,一开始有一个数\(0\), 每 ...
- AtCoder AGC035E Develop (DP、图论、计数)
题目链接 https://atcoder.jp/contests/agc035/tasks/agc035_e 题解 没想出来最后一步DP宛如智障-- 考虑一个数\(x\notin S\)的条件是\(x ...
- AtCoder AGC038D Unique Path (图论)
题目链接 https://atcoder.jp/contests/agc038/tasks/agc038_d 题解 orz zjr神仙做法 考虑把所有\(C_i=0\)的提示的两点连边,那么连完之后的 ...
- AtCoder AGC022C Remainder Game (图论)
题目链接 https://atcoder.jp/contests/agc022/tasks/agc022_c 题解 大水题一道 就他给的这个代价,猜都能猜到每个数只能用一次 仔细想想,我们肯定是按顺序 ...
- AtCoder AGC036D Negative Cycle (图论、DP)
题目链接 https://atcoder.jp/contests/agc036/tasks/agc036_d 题解 这都是怎么想出来的啊..目瞪口呆系列.. 第一步转化至关重要: 一张图中不存在负环意 ...
最新文章
- 单链表-单链表A拆分为A(偶)和C(奇) (尾插法建表)
- IOS设计模式第六篇之适配器设计模式
- Linux环境变量配置出错,导致登录不了......
- linux jdk1.4 安装,linux安装jdk1.4.2
- java中CardLayout的使用方法
- MySQL事件与定时器,mysql下存储过程与定时器
- solidity数据位置-memory,storage和calldata
- Asp.net中关于上传文件的各项基本操作
- python在字符串结尾加反斜杠_Python原始字符串和尾部反斜杠
- Bailian3719 学生信息用qsort排序【排序+字符串库函数】
- 生命中的七堂课(转)
- 大型门户网站架构分析[转]
- SHELL下获得指定进程的进程号,并截取为整数
- 惠普服务器硬盘指示灯不亮或显示蓝色
- 脚本中fi是什么意思
- 产品经理与程序员之间的孽缘发展历程
- Tensorflow的安装与报错
- Intel(Altera)FPGA的SOF转JIC文件和下载详细教程
- vivado中ZYNQ详解(主要用于PS和PL之间的工作衔接)
- Linux硬盘分区mbr还是gpt,涨姿势:MBR和GPT硬盘分区表的那些事儿