Description

你准备给弟弟 Ike 买一件礼物,但是,Ike 挑选礼物的方式很特别:他只喜欢那些能被他排成有序形状的东西。

你准备给 Ike 买一个风铃。风铃是一种多层的装饰品,一般挂在天花板上。

每个风铃都包含一些由竖直线连起来的水平杆。每根杆的两头都有线连接,下面或者挂着另一根水平杆,或者挂着一个玩具。下面是一个风铃的例子:

为了满足弟弟,你需要选一个满足下面两个条件的风铃:

(1) 所有的玩具都在同一层(也就是说,每个玩具到天花板之间的杆的个数是一样的)或至多相差一层。

(2) 对于两个相差一层的玩具,左边的玩具比右边的玩具要更靠下一点。

风铃可以按照下面的规则重新排列:任选一根杆,将杆两头的线“交换”。也就是解开一根杆左右两头的线,然后将它们绑到杆的另一头。这个操作不会改变更下面的杆上线的排列顺序。正在训练信息学奥林匹克的你,决定设计一个算法,判断能否通过重新排列,将一个给定的风铃变为 Ike 喜欢的样子。

考虑上面的例子,上图中的风铃满足条件(1),却不满足条件(2)——最左边的那个玩具比它右边的要高。

但是,我们可以通过下面的步骤把这个风铃变成一个 Ike 喜欢的:

第一步,将杆 1 的左右两边交换,这使得杆 2 和杆 3 的位置互换,交换的结果如下图所示:

第二步,也是最后一步,将杆 2 的左右两边交换,这使得杆 4 到了左边,原来在左边的玩具到了右边,交换的结果发下图所示:

现在的这个风铃就满足 Ike 的条件了。

你的任务是:给定一个风铃的描述,求出最少需要多少次交换才能使这风铃满足 Ike 的条件(如果可能)

Input

输入的第一行包含一个整数 n(1≤n≤100 000),表示风铃中有多少根杆。

接下来的 n 行描述杆的连接信息。这部分的第 i 行包含两个由空格分隔的整数 li和 ri,描述杆 i 的左右两边悬挂的东西。如果挂的是一个玩具,则对应的值为-1,否则为挂在下面的杆的编号

Output

输出仅包含一个整数。表示最少需要多少次交换能使风铃满足 Ike 的条件。如果不可能满足,输出-1。

Sample Input

6

2 3

-1 4

5 6

-1 -1

-1 -1

-1 -1

Sample Output

2


想法

才不会说我是看这个题目好玩才去做的呢

这个题目让我想起了林清玄的散文《风铃》:

有了风铃,风虽然吹过了,还留下美妙的声音

有了心的风铃,生命即使走过了,也会留下动人的痕迹

每一次起风的时候,每一步岁月的脚步,都会那样真实地存在。

等等,跑题了!

这个题就是树形dp嘛,注意判断几种不行的情况:

1.风铃相差层数>1

2.在满足风铃相差层数为1的情况下,把在上面一层的风铃统称为F,把下面一层的风铃统称为G

在某一节点,其两个子节点中都既有F又有G

然后注意各种细节就好了(自古树形dp细节多qwq)


代码

#include<cstdio>
#include<iostream>
#include<algorithm> using namespace std; const int N = 100005; int ch[N][2],pa[N],dep[N];
int n,rt; int m,d[N],t;
void get_dep(int u){
for(int i=0;i<2;i++){
if(ch[u][i]!=-1){
dep[ch[u][i]]=dep[u]+1;
get_dep(ch[u][i]);
}
else d[m++]=dep[u]+1,t=max(t,d[m-1]);
}
}
int sz[N],num[N]; //num表示该节点子树中F与G的总和,sz表示该节点子树中F个数
void dfs0(int u){
for(int i=0;i<2;i++){
if(ch[u][i]!=-1){
dfs0(ch[u][i]);
num[u]+=num[ch[u][i]]; sz[u]+=sz[ch[u][i]];
}
else {
num[u]++;
if(dep[u]+1==t-1) sz[u]++;
}
}
} int flag;
int dfs(int u){
if(sz[u]==0 || sz[u]==num[u]) return 0;
if(ch[u][0]!=-1 && ch[u][1]!=-1){
if(sz[ch[u][0]]==0) return dfs(ch[u][1]);
if(sz[ch[u][1]]==0) return dfs(ch[u][0])+1;
if(sz[ch[u][0]]==num[ch[u][0]]) return dfs(ch[u][1])+1;
if(sz[ch[u][1]]==num[ch[u][1]]) return dfs(ch[u][0]);
flag=0; return 0;
}
if(ch[u][0]==-1 && ch[u][1]!=-1){
if(sz[ch[u][1]]==0) return 1;
return dfs(ch[u][1])+1;
}
if(ch[u][0]!=-1 && ch[u][1]==-1){
if(sz[ch[u][0]]==0) return 0;
return dfs(ch[u][0]);
}
return 0;
} int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&ch[i][0],&ch[i][1]);
if(ch[i][0]!=-1) pa[ch[i][0]]=i;
if(ch[i][1]!=-1) pa[ch[i][1]]=i;
} for(int i=1;i<=n;i++) if(!pa[i]) { rt=i; break; }
dep[rt]=1; get_dep(rt); flag=1;
for(int i=0;i<m;i++) if(d[i]<t-1) flag=0;
if(flag==0) { printf("-1"); return 0; } dfs0(rt);
if(sz[rt]==0) { printf("0"); return 0; } int ans=dfs(rt);
if(flag==0) printf("-1");
else printf("%d",ans); return 0;
}

[洛谷P3621] [APIO2007] 风铃的更多相关文章

  1. 洛谷 P3621 [APIO2007]风铃【贪心】

    没有算法,但是要注意细节. 首先无解的情况,显然的是最小深度的叶子节点和最大深度的叶子节点的深度差大于1:还有一种比较难想,就是如果一个点的左右子树都有最大和最小深度的叶子节点,这样交换左右子树也不行 ...

  2. 洛谷P3621风铃

    传送门啦 分析: 这个题看起来像是个树形dp,嗯,就是看起来像. 所以我们就按树形dp的思路去分析就好了,这个题是一个树形dp的变形题. 和以前建树是一样的,我们用邻接表来进行储存.利用邻接表的特性, ...

  3. 洛谷 P3622 [APIO2007]动物园【状压dp】

    看成网络流建图想了好久... 实际上5个是可以状压的 设f[i][k]为到第i个围栏状态为k的方案数,因为考虑到重复,设g[i][k]记录i开始,状态为k的孩子有几个 状态转移很好想:f[j][k]= ...

  4. 洛谷1640 bzoj1854游戏 匈牙利就是又短又快

    bzoj炸了,靠离线版题目做了两道(过过样例什么的还是轻松的)但是交不了,正巧洛谷有个"大牛分站",就转回洛谷做题了 水题先行,一道傻逼匈牙利 其实本来的思路是搜索然后发现写出来类 ...

  5. 洛谷P1352 codevs1380 没有上司的舞会——S.B.S.

    没有上司的舞会  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond       题目描述 Description Ural大学有N个职员,编号为1~N.他们有 ...

  6. 洛谷P1108 低价购买[DP | LIS方案数]

    题目描述 “低价购买”这条建议是在奶牛股票市场取得成功的一半规则.要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买:再低价购买”.每次你购买一支股票,你必须用低于你上次购买它的价格购买它 ...

  7. 洛谷 P2701 [USACO5.3]巨大的牛棚Big Barn Label:二维数组前缀和 你够了 这次我用DP

    题目背景 (USACO 5.3.4) 题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方.我们假定,他的农场划分成 N ...

  8. 洛谷P1710 地铁涨价

    P1710 地铁涨价 51通过 339提交 题目提供者洛谷OnlineJudge 标签O2优化云端评测2 难度提高+/省选- 提交  讨论  题解 最新讨论 求教:为什么只有40分 数组大小一定要开够 ...

  9. 洛谷P1371 NOI元丹

    P1371 NOI元丹 71通过 394提交 题目提供者洛谷OnlineJudge 标签云端评测 难度普及/提高- 提交  讨论  题解 最新讨论 我觉得不需要讨论O long long 不够 没有取 ...

随机推荐

  1. H3C 端口隔离基本配置

  2. gitLab操作规范和项目流程

    刚做完一个项目并且艰难得上线,对整个项目流程和gitLab规范 有了一些心得,给新来的同学普及一下. 最先产品会写一篇需求文档,咱们要先看需求文档对项目有一个大致了解,然后产品喊后端.ui.前端  一 ...

  3. dll中全局变量在外部进行引用

    在Windows中实际导出全局变量,您必须使用类似于export / import语法的语法,例如: #ifdef COMPILING_THE_DLL #define MY_DLL_EXPORT ex ...

  4. HDU1556 Color the ball & 牛客 contest 135-I 区间 [差分标记]

    一.差分标记介绍 差分标记用来解决针对区间(修改-查询)的问题,复杂度比线段树要更低.推荐这个博客. 例如,给数组中处于某个区间的数进行加减操作,然后查询某个位置上数的变化值. 二.HDU1556 C ...

  5. Hibernate管理Session

    Hibernate自身提供了三种管理Session对象的方法 Session对象的生命周期与本地线程绑定 Session对象的生命周期与JTA事务绑定 Hibernate委托程序管理Session对象 ...

  6. CentOS遇到Qt编译问题(error: cannot find -lGL)

    1.安装Qt,进入CentOS系统的终端,依次执行以下命令 chmod +x qt-opensource-Linux-x64-5.5.1.run ./qt-opensource-linux-x64-5 ...

  7. looping through multiple lists

    map: 最大长度输出: zip: 最短输出: third: 有序排列: a = ['a1', 'a2', 'a3'] b = ['b1', 'b2'] print "Map:" ...

  8. 阿里面试官让我讲讲Unicode,我讲了3秒说没了,面试官说你可真菜

    本文首发于微信公众号:程序员乔戈里 乔哥:首先说说什么是Unicode.码点吧~要想搞懂,这些概念必须清楚 什么是Unicode? 下图来自http://www.unicode.org/standar ...

  9. pytorch :: Dataloader中的迭代器和生成器应用

    在使用pytorch训练模型,经常需要加载大量图片数据,因此pytorch提供了好用的数据加载工具Dataloader. 为了实现小批量循环读取大型数据集,在Dataloader类具体实现中,使用了迭 ...

  10. 深入浅出 Viewport 设计原理

    Viewport 是 HTML5 针对移动端开发新增的一个 meta 属性, 它的作用是为同一网页在不同设备的呈现,提供响应式解决方案.这篇文章尝试通过循序渐进的方式,逐层探索 Viewport 的设 ...