Codeforces 19E&BZOJ 4424 Fairy(好题)
日常自闭(菜鸡qaq)。不过开心的是看了题解之后1A了。感觉这道题非常好,必须记录一下,一方面理清下思路,一方面感觉自己还没有完全领会到这道题的精髓先记下来以后回想。
题意:给定 n 个点,m 条边的无向图,可以从图中删除一条边,问删除哪些边可以使图变成一个二分图。
看到二分图,我们肯定会想到奇环。要删除一条边使得剩下的图变成二分图,那么必定剩下的图也不能存在奇环。所以要删除的边都必须经过所有的奇环。这比较好想,但是还有一个难想一点的条件,要删除的边也不能经过任何的偶环,这是因为如果这条边经过了偶环,哪怕删除了这条边剩下的边也会形成新的奇环。为什么呢?画一下图就发现,假定奇环长度为A,偶环长度为B,他们共享的边长度为C,那么他们能形成新的长度为A+B-2*C长度的环,显然这个数是奇数。
综上,能删除的边满足上诉两个条件。我们得到这样一个算法:对所有奇环的边+1,对所有偶环的边-1,最后边值等于奇环个数的就是满足条件的边。 那么我们可以考虑用差分完成这个事情,用d[x]代表dfs树进入x点的边的差分值。染色的过程差分,染完色之后计算便值即可。
当然这道题还没完,以上的过程我们只考虑了dfs树边的情况,但是返祖边(非树边)呢?我们继续思考:经过上面的思考我们还是只考虑奇环上的返祖边,仔细画图观察:在dfs搜索树上,一个奇环返祖边只会属于一个奇环。根据我们上边的结论:边必须要经过所有奇环,可以得到:奇环返祖边能满足条件当且仅当图上只有一个奇环。
接下来还得注意一个小细节:自环。自环我们可以当中奇环,但是这种奇环没有返祖边,所以我们得特殊处理。
呼呼,到这里我们终于能AC了。
细节详见代码以注释:
#pragma comment(linker,"/STACK:102400000,102400000")
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+;
int n,m,odd,rec,num,col[N],vis[N],tag[N],dfn[N];
vector<int> ans; int cnt=,head[N],nxt[N<<],to[N<<],id[N<<];
void add_edge(int x,int y,int z) {
nxt[++cnt]=head[x]; to[cnt]=y; id[cnt]=z; head[x]=cnt;
} void dfs1(int x,int t,int in) {
col[x]=t; dfn[x]=++num;
for (int i=head[x];i;i=nxt[i]) {
if (i==(in^)) continue; //这样能处理重边的情况
int y=to[i];
if (!col[y]) dfs1(y,-t,i);
else {
if (dfn[x]<dfn[y]) continue; //这是一个细节,dfn[x]比dfn[y]大的才是返祖边
if (col[x]==col[y]) { //奇环
odd++; rec=i;
tag[x]++; tag[y]--;
} else { //偶环
tag[x]--; tag[y]++;
}
}
}
} void dfs2(int x,int in) {
vis[x]=;
for (int i=head[x];i;i=nxt[i]) {
if (i==(in^)) continue;
int y=to[i];
if (!vis[y]) {
dfs2(y,i);
tag[x]+=tag[y]; //累计子树差分值得到 x入边值
}
}
if (tag[x]==odd) ans.push_back(in); //满足条件的边
} int main()
{
cin>>n>>m;
for (int i=;i<=m;i++) {
int x,y; scanf("%d%d",&x,&y);
if (x==y) { //特别处理自环的情况
odd++; add_edge(,,i); rec=cnt; continue;
}
add_edge(x,y,i); add_edge(y,x,i);
} for (int i=;i<=n;i++)
if (!col[i]) dfs1(i,,); //染色
for (int i=;i<=n;i++)
if (!vis[i]) dfs2(i,); //计算边值 if (odd==) {
cout<<m<<endl;
for (int i=;i<=m;i++) printf("%d ",i);
} else {
if (odd==) ans.push_back(rec); //奇环返祖边
cout<<ans.size()<<endl;
sort(ans.begin(),ans.end());
for (int i=;i<ans.size();i++) printf("%d ",id[ans[i]]);
}
return ;
}
Codeforces 19E&BZOJ 4424 Fairy(好题)的更多相关文章
- Codeforces Round #378 (Div. 2) D题(data structure)解题报告
题目地址 先简单的总结一下这次CF,前两道题非常的水,可是第一题又是因为自己想的不够周到而被Hack了一次(或许也应该感谢这个hack我的人,使我没有最后在赛后测试中WA).做到C题时看到题目情况非常 ...
- Codeforces 828B Black Square(简单题)
Codeforces 828B Black Square(简单题) Description Polycarp has a checkered sheet of paper of size n × m. ...
- HYSBZ(BZOJ) 4300 绝世好题(位运算,递推)
HYSBZ(BZOJ) 4300 绝世好题(位运算,递推) Description 给定一个长度为n的数列ai,求ai的子序列bi的最长长度,满足bi&bi-1!=0(2<=i<= ...
- BZOJ第一页刷题计划
BZOJ第一页刷题计划 已完成:67 / 90 [BZOJ1000]A+B Problem:A+B: [BZOJ1001][BeiJing2006]狼抓兔子:最小割: [BZOJ1002][FJOI2 ...
- http://codeforces.com/gym/100623/attachments E题
http://codeforces.com/gym/100623/attachments E题第一个优化它虽然是镜像对称,但它毕竟是一一对称的,所以可以匹配串和模式串都从头到尾颠倒一下第二个优化,与次 ...
- http://codeforces.com/gym/100623/attachments H题
http://codeforces.com/gym/100623/attachments H题已经给出来的,包括后来添加的,都累加得到ans,那么从1-ans都是可以凑出来的,如果ans<a[n ...
- Codeforces Round #612 (Div. 2) 前四题题解
这场比赛的出题人挺有意思,全部magic成了青色. 还有题目中的图片特别有趣. 晚上没打,开virtual contest打的,就会前三道,我太菜了. 最后看着题解补了第四道. 比赛传送门 A. An ...
- bzoj 4424: Cf19E Fairy && codeforces 19E. Fairy【树形dp】
参考:https://blog.csdn.net/heheda_is_an_oier/article/details/51131641 这个找奇偶环的dp1真是巧妙,感觉像tarjan一样 首先分情况 ...
- Guard Duty (medium) Codeforces - 958E2 || (bzoj 2151||洛谷P1792) 种树 || 编译优化
https://codeforces.com/contest/958/problem/E2 首先求出N个时刻的N-1个间隔长度,问题就相当于在这些间隔中选K个数,相邻两个不能同时选,要求和最小 方法1 ...
随机推荐
- C语言实现Windows下获取IP和MAC地址。
C语言实现Windows下获取IP和MAC地址. #include <winsock2.h> #include <stdio.h> #include <stdlib.h& ...
- Codeforces 360E 贪心 最短路
题意及思路:https://blog.csdn.net/huanghongxun/article/details/49846927 在假设所有边都是最大值的情况下,如果第一个人能比第二个人先到,那就缩 ...
- Linux中的系统服务_02
Linux中的系统服务_02 1. 在linux增加服务后,如果要实现随着操作系统的启动而启动,需要是用chkconfig命令,加入到系统服务中. 但是对于的脚本的表头,需要增加如下内容 #!/bin ...
- vue-axios请求
<template> <div> <div v-if="!repoUrl">loding</div> <div v-else& ...
- Jquery的idTabs使用
http://www.sunsean.com/idTabs/jquery.idTabs.min.js idTabs使用基本介绍如下: 通常的使用方法如下: <div id="usual ...
- 关键字group by 、 Having的 用法
概述 GROUP BY我们可以先从字面上来理解,GROUP表示分组,BY后面写字段名,就表示根据哪个字段进行分组,如果有用Excel比较多的话,GROUP BY比较类似Excel里面的透视表. GRO ...
- shell脚本学习(1)入门
1脚本语言和编译型语言的区别:编译型的要从源码转换成目标代码,多运行于底层.脚本语言有解释器读入程序代码, 转成内部形式再执行. 2脚本语言,写的时间快,一般有awk,pwel, python Rub ...
- eclipse 中的.classpath和.project文件的具体作用(转)
转载博客:http://www.cnblogs.com/panjun-Donet/archive/2010/08/25/1807780.html .project是项目文件,项目的结构都在其中定义,比 ...
- 2018icpc南京/gym101981 A Adrien and Austin 博弈
题意: n个连续排列的石子,每次只许拿连续的(中间没有空格)的k个,问你谁必胜 题解: 简单博弈,特判总数为0,k=1两种情况,其他情况先拿必胜,方法是拿掉中间的,然后对方怎么拿你镜面拿就行. #in ...
- php开发面试题---lavarel和tp的区别是什么(呕心整理)
php开发面试题---lavarel和tp的区别是什么(呕心整理) 一.总结 一句话总结: 反思的回顾非常有用,因为决定了我的方向和技巧 以战养己,这是非常非常好的方式 主要从大小.功能.安全性.操作 ...