[JZOJ5969] 世界线修理(欧拉回路)
题目
描述
>
题目大意
给你两棵树,让你对每个点赋权,使得在两棵树中的任意子树的和绝对值为111。
比赛思路
其实我一开始理解错题意了……
正解
首先,我们可以判断每个点权的奇偶性。
如果一个点有偶数个儿子,显然它们的和为偶数,所以这个点权为奇数。
如果一个点有奇数个儿子,显然它们的和为奇数,所以这个点权为偶数。
所以在两棵树中,分别计算它儿子的个数。如果它们的奇偶性不一样,那么一定impossible。
现在有一个问题,如果它们的奇偶性一样,那么是否一定有一种可行的方案呢?
的确是可行的。
然后发现必定有一种可行的方案满足每个点的权值只能为−1,0,1-1,0,1−1,0,1
感性理解一下可能就出来了。
咳咳,先不要讨论这么多。
接下来有一个巧妙的东西,叫欧拉回路。
我也不知道出题人的脑洞究竟有多大,这题居然可以和欧拉回路建立起联系!
首先,我们把两个树构出来。其中对于根节点,我们用一个超级源来连接它们。
显然对于每一个度数为偶数的点,因为它们有奇数个儿子,所以它们的权值为000。
反之,对于每一个度数为奇数的点,它们的权值为−1-1−1或111。
然后枚举每一个点,如果这个点的度数为奇数,那么就将两个树中对应的点连接起来。(这条边叫横插边)
然后我们就发现这个图中,每个点的度数都是偶数,那么就一定存在一个欧拉回路。
随便从一个点出发,找出一条欧拉回路。
随便以某个树为准,对于每一个横插边,看看它们的方向,如果是进入这棵树,那么这个横插边对应的两点的点权为−1-1−1,否则为111。
当然,反过来也一样。
然后答案就出来了。
能想出这个解法的人一定是个天才……
接下来我们来证明这个解法为什么是正确的。
首先设四类环:
一类环为,从某个点开始,先走儿子边,然后从儿子边回来。
二类环为,从某个点开始,先走儿子边,然后从父亲边回来。
三类环为,从某个点开始,先走横插边,然后从父亲边回来。
四类环为,从某个点开始,先走儿子边,然后从横插边回来。
当然,每个环的走向反过来都是等价的。
然后考虑每个环的代价:
对于一类环,就是在两棵树之间跳来跳去,但代价都是在这个点的子树以内计算的。进来的代价为−1-1−1,出去的代价为111,所以一类环的代价是000。
四类环也是同样的道理,代价为000.
对于二类环,也是在两棵树之间跳来跳去,但是,由于最后从父亲边回来,意味着最后一次从横插边跳回来的时候计算的代价不在这个点的子树内,所以二类环的代价是−1-1−1或111。
三类环也是同样的道理,代价也是−1-1−1或111。
然后我们再看看每一个点:
如果一个点有奇数个儿子,那么它的度数为偶数,是没有横插边的。所以只有若干个一类环和一个二类环,所以代价为−1-1−1或111。
如果一个点有偶数个儿子,那么它有横插边。所以,要么是若干个一类环和一个三类环,要么是若干个一类环和一个二类环和一个四类环。然后可以发现代价都是−1-1−1或111。
得证……
还有一个问题,为什么要设置一个超级源?
仔细想一下,设置一个超级源之后,根节点就变得跟普通点一样了,它们的性质也一样。
而且你会发现,如果不设超级源,那么仅仅用这个方法并不成立,或许要加点特判什么的……
代码
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
int n;
int fa1[N+1],fa2[N+1];
int rd1[N+1],rd2[N+1];
struct EDGE{
int to;
EDGE *las;
bool bz;
} e[N*6+1];
int ne=-1;
EDGE *last[N*2+1];
#define rev(ei) (e+(int((ei)-e)^1))
inline void link(int u,int v){
e[++ne]={v,last[u],1};
last[u]=e+ne;
e[++ne]={u,last[v],1};
last[v]=e+ne;
}
int w[N*6+1],nw;
void dfs(int);
int ans[N+1];
int main(){
scanf("%d",&n);
for (int i=1;i<=n;++i){
scanf("%d",&fa1[i]);
if (fa1[i]!=-1)
rd1[fa1[i]]++;
}
for (int i=1;i<=n;++i){
scanf("%d",&fa2[i]);
if (fa2[i]!=-1)
rd2[fa2[i]]++;
}
for (int i=1;i<=n;++i)
if ((rd1[i]^rd2[i])&1){//当奇偶性不同时
printf("IMPOSSIBLE\n");
return 0;
}
printf("POSSIBLE\n");
for (int i=1;i<=n;++i){
//i<<1表示i在第一棵树的点,i<<1|1表示i在第二棵树的点
link(i<<1,fa1[i]!=-1?fa1[i]<<1:0);
link(i<<1|1,fa2[i]!=-1?fa2[i]<<1|1:0);
if (~rd1[i]&1)
link(i<<1,i<<1|1);
}
w[0]=1<<1;
dfs(1<<1);
for (int i=1;i<=nw;++i)
if ((w[i-1]^w[i])==1){//如果两个点互为对应点
if (w[i]&1)
ans[w[i]>>1]=-1;
else
ans[w[i]>>1]=1;
}
for (int i=1;i<=n;++i)
printf("%d ",ans[i]);
return 0;
}
void dfs(int x){//求欧拉回路
for (EDGE *ei=last[x];ei;ei=last[x]){
last[x]=ei->las;//将这条边删除
if (ei->bz){
rev(ei)->bz=ei->bz=0;
dfs(ei->to);
}
}
w[++nw]=x;
}
总结
说实话,其实感觉上这题没什么好总结的。
因为这题能想出来实在是太变态了。
[JZOJ5969] 世界线修理(欧拉回路)的更多相关文章
- USACO 3.3.1 Riding the Fences 骑马修栅栏(欧拉回路)
Description 农民John每年有很多栅栏要修理.他总是骑着马穿过每一个栅栏并修复它破损的地方. John是一个与其他农民一样懒的人.他讨厌骑马,因此从来不两次经过一个一个栅栏.你必须编一个程 ...
- 洛谷P2731 骑马修栅栏 [欧拉回路]
题目传送门 骑马修栅栏 题目背景 Farmer John每年有很多栅栏要修理.他总是骑着马穿过每一个栅栏并修复它破损的地方. 题目描述 John是一个与其他农民一样懒的人.他讨厌骑马,因此从来不两次经 ...
- ACM/ICPC 之 混合图的欧拉回路判定-网络流(POJ1637)
//网络流判定混合图欧拉回路 //通过网络流使得各点的出入度相同则possible,否则impossible //残留网络的权值为可改变方向的次数,即n个双向边则有n次 //Time:157Ms Me ...
- [poj2337]求字典序最小欧拉回路
注意:找出一条欧拉回路,与判定这个图能不能一笔联通...是不同的概念 c++奇怪的编译规则...生不如死啊... string怎么用啊...cincout来救? 可以直接.length()我也是长见识 ...
- ACM: FZU 2112 Tickets - 欧拉回路 - 并查集
FZU 2112 Tickets Time Limit:3000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u P ...
- UVA 10054 the necklace 欧拉回路
有n个珠子,每颗珠子有左右两边两种颜色,颜色有1~50种,问你能不能把这些珠子按照相接的地方颜色相同串成一个环. 可以认为有50个点,用n条边它们相连,问你能不能找出包含所有边的欧拉回路 首先判断是否 ...
- POJ 1637 混合图的欧拉回路判定
题意:一张混合图,判断是否存在欧拉回路. 分析参考: 混合图(既有有向边又有无向边的图)中欧拉环.欧拉路径的判定需要借助网络流! (1)欧拉环的判定:一开始当然是判断原图的基图是否连通,若不连通则一定 ...
- codeforces 723E (欧拉回路)
Problem One-Way Reform 题目大意 给一张n个点,m条边的无向图,要求给每条边定一个方向,使得最多的点入度等于出度,要求输出方案. 解题分析 最多点的数量就是入度为偶数的点. 将入 ...
- UVa 12118 检查员的难题(dfs+欧拉回路)
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...
随机推荐
- Idea中创建maven骨架的命令
如下:通过命令化在Idea中创建骨架成功后,以后项目直接引用导入骨架直接在依赖框架上面进行相关模块开发: 1.mvn archetype:create-from-project 2.mvn clean ...
- [JZOJ3692] 【SRM 611】ElephantDrinking
题目 题目大意 我真的不知道怎么用简短的语言表述出来-- 直接看题目吧-- 正解 假设只有左边和上边延伸过来的,那似乎很好办:设\(f_{i,j}\)表示左上方到\((i,j)\)所形成的矩形中,如果 ...
- SQL Server SQLFetch()
{ /* 摘要 SQLFetch从结果集中提取下一个数据行集, 并返回所有绑定列的数据. 语法 C++ SQLRETURN SQLFetch( SQLHSTMT StatementHandle ...
- Oracle大数据SQL语句优化
1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索 ...
- C++——多态
1. 多态定义的构成条件 多态是在不同继承关系的类对象,去调同一函数,产生了不同的行为. 就是说,有一对继承关系的两个类,这两个类里面都有一个函数且名字.参数.返回值均相同,然后我们通过调用函数来实现 ...
- DP杂题2
1.邦邦的大合唱站队 https://www.luogu.org/problem/show?pid=3694 XY说这是道简单的签到题,然后我大概是普及组都拿不到三等的那种了.. 插入题解.写得太好了 ...
- System.IO.Directory.cs
ylbtech-System.IO.Directory.cs 1.返回顶部 1. #region 程序集 mscorlib, Version=4.0.0.0, Culture=neutral, Pub ...
- Delphi编写后台监控软件
Delphi编写后台监控软件 文章来源:Delphi程序员之家 后台监控软件,为了达到隐蔽监控的目的,应该满足正常运行时,不显示在任务栏上,在按Ctrl+Alt+Del出现的任 ...
- P1417 烹调方案 /// DP(假设 简化公式 排序)
题目大意: https://www.luogu.org/problemnew/show/P1417 题解 看第一份方法的公式 排序后01背包 #include <bits/stdc++.h> ...
- linux sudo命令失败 提示sudo:/usr/bin/sudo 必须属于用户 ID 0(的用户)并且设置 setuid 位
sudo:/usr/bin/sudo 必须属于用户 ID 0(的用户)并且设置 setuid 位 一.前言 这是一个神奇的错误,缘由是因为有人将/usr/bin/sudo的权限改为777或其他. 解决 ...
>