JZOJ 3506. 【NOIP2013模拟11.4A组】善良的精灵
来源:互联网 发布:mac 流程图软件 免费 编辑:程序博客网 时间:2024/05/16 18:18
Description
从前有一个善良的精灵。
一天,一个年轻人B找到她并请他预言他的未来。这个精灵透过他的水晶球看到这个年轻人将要遇见一个非常美丽的公主并要娶她。。精灵在一张纸上画了N个点并用一些线段将他们连起来,每条线段两端连着不同的点。画完了之后,精灵让年轻人去除一条线段。然后精灵尝试将每个点用红色或者蓝色进行染色,同时使得那里没有一条线段的两端是相同的颜色。如果精灵能够成功染色,这个预言就能成真。
年轻人想要遇见那位公主,因此他请求你去帮助他,找到所有的删除之后能对图进行成功染色的线段。
Input
输入文件中的第一行为两个整数N,M,分别表示点的个数和线段的条数。
接下来的M行,描述了每条线段,每行有两个整数v,u(1<=v,u<=n),表示线段两端的点的标号。注意:没有线段会重复出现。
Output
输出文件中的第一行为一个整数K,即删除之后能对点进行染色的线段的个数。
接下来的一行包含K个从小到大的数字,数字之间用一个空格隔开,行末没有空格,表示满足条件的线段的标号。每条线段的标号为读入顺序的标号。
Sample Input
输入1:
4 4
1 2
1 3
2 4
3 4
输入2:
4 5
1 2
2 3
3 4
4 1
1 3
Sample Output
输出1:
4
1 2 3 4
输出2:
1
5
Data Constraint
对于50%的数据,满足:N,M<=1000;
对于100%的数据,满足:N,M<=10000。
Solution
首先,设
fodd[i],feven[i],godd[x],geven[x],sum 。fodd[i] 表示 编号为i 的边 被多少个 奇数环 包含;feven[i] 表示 编号为i 的边 被多少个 偶数环 包含;godd[x] 表示 编号为x 的点 的奇数环标记;geven[i] 表示 编号为x 的点 的偶数环标记;sum 表示奇数环的总个数。(意义用法稍后讲解)众所周知,如果有奇数环就要果断删边,偶数环则应保留。
所以说,一条边
i 可以被删,当且仅当fodd[i]=sum 并且feven[i]=0 。即:被所有奇数环包含,没有偶数环经过。
那么问题就转换成如何在线性时间复杂度内处理出 F 数组。
考虑把图当做树来看,处理出深度数组
dep[i] ;若当前点为
u ,连向v ,而dep[v] 有值且小于dep[u] ,则说明出现了一个环。那么用
dep[u]−dep[v] (环内其他点的个数) 的奇偶性可以知道这是一个奇数环还是偶数环。之后累加
fodd/even[i] ,可以则累加sum ,接着:(关键!)godd/even[u]++,godd/even[v]−− ,即打一个 Tag 标记(类似差分约束),如下图:
那么如果
sum=0 (没有奇数环)就所有边都可以删,全部输出啦!紧接着,再做一遍 DFS ,像统计子节点个数一样从下至上累加 Tag 标记;
中途更改 F 数组即可,注意奇偶对应。如下图:
- 那么计算答案即可!
Code
#include<cstdio>using namespace std;const int N=10001;int tot,sum;int first[N],next[N*2],en[N*2],w[N*2];int fodd[N],feven[N],godd[N],geven[N];int ans[N],dep[N];bool bz[N*2],vis[N];inline int read(){ int data=0; char ch=0; while(ch<'0' || ch>'9') ch=getchar(); while(ch>='0' && ch<='9') data=data*10+ch-'0',ch=getchar(); return data;}inline void insert(int x,int y,int z){ next[++tot]=first[x]; first[x]=tot; en[tot]=y; w[tot]=z;}inline void dfs(int x,int fa){ dep[x]=dep[fa]+1; for(int i=first[x];i;i=next[i]) if(en[i]!=fa) { if(!dep[en[i]]) { bz[i]=true; dfs(en[i],x); }else if(dep[en[i]]<dep[x])//Link if((dep[x]-dep[en[i]])&1) { geven[en[i]]--; geven[x]++; feven[w[i]]=1;//Even }else { godd[en[i]]--; godd[x]++; fodd[w[i]]=1;//Odd sum++; } }}inline void find(int x){ vis[x]=true; for(int i=first[x];i;i=next[i]) if(bz[i]) { find(en[i]); fodd[w[i]]=godd[en[i]]; feven[w[i]]=geven[en[i]]; godd[x]+=godd[en[i]]; geven[x]+=geven[en[i]]; }}int main(){ int n=read(),m=read(); for(int i=1;i<=m;i++) { int x=read(),y=read(); insert(x,y,i); insert(y,x,i); } for(int i=1;i<=n;i++) if(!dep[i]) dfs(i,0); if(!sum) { printf("%d\n",m); for(int i=1;i<=m;i++) printf("%d ",i); return 0; } for(int i=1;i<=n;i++) if(!vis[i]) find(i); for(int i=1;i<=m;i++) if(!feven[i] && fodd[i]==sum) ans[++ans[0]]=i; printf("%d\n",ans[0]); for(int i=1;i<=ans[0];i++) printf("%d ",ans[i]); return 0;}
- JZOJ 3506. 【NOIP2013模拟11.4A组】善良的精灵
- JZOJ 3506. 【NOIP2013模拟11.4A组】善良的精灵
- 【NOIP2013模拟11.4A组】善良的精灵
- jzoj. 3505. 【NOIP2013模拟11.4A组】积木(brick)
- JZOJ 3505. 【NOIP2013模拟11.4A组】积木(brick)
- jzoj. 3518. 【NOIP2013模拟11.6A组】进化序列(evolve)
- JZOJ 3518. 【NOIP2013模拟11.6A组】进化序列(evolve)
- JZOJ 3526. 【NOIP2013模拟11.7A组】不等式(solve)
- jzoj. 3526. 【NOIP2013模拟11.7A组】不等式(solve)
- jzoj. 3523. 【NOIP2013模拟11.7A组】JIH的玩偶(tree)
- [jzoj]3505. 【NOIP2013模拟11.4A组】积木(brick) (排列组合vsDP)
- JZOJ-senior-3502. 【NOIP2013模拟11.4B组】方格游戏
- [jzoj]3511. 【NOIP2013模拟11.5A组】cza的蛋糕(cake)(DP嵌套dfs【快】或DP【慢】)
- 【NOIP2013模拟11.4A组】游乐场
- 【NOIP2013模拟11.4A组】积木(brick)
- jzoj. 3519. 【NOIP2013模拟11.6A组】灵能矩阵(pylon)
- [jzoj]3526. 【NOIP2013模拟11.7A组】不等式(solve)(类欧几里得)
- [jzoj]3503. 【NOIP2013模拟11.4B组】粉刷(paint)(位运算优化)
- 蓝桥杯之趣味算式
- Android插件化系列第(二)篇---动态加载技术之应用换肤
- linux 下mysql数据的导入、导出
- Spring 对象XML映射
- windows 10 high dpi problem fix
- JZOJ 3506. 【NOIP2013模拟11.4A组】善良的精灵
- leetcode--112. Path Sum
- CSU-1268
- Retrofit简单的实例
- Java 8 λ表达式
- ubuntu开启SSH服务远程登录
- F - Flying to the Mars HDU - 1800
- Git学习使用(五):分支管理<Ⅰ>
- Servlet 生命周期、工作原理