01 on Tree

题目链接:luogu AT3957

题目大意

有一棵根为 \(1\) 的树,每个节点有个值 \(0\) 或 \(1\)。

然后每次你可以把一个没有父亲的点删除,然后把值放进一个数组里。

要你得出的数组逆序对尽可能少,要输出这个最小的逆序对个数。

思路

那我们会发现从根节点开始删会很麻烦,很难处理,那我们考虑反着来:从叶节点开始不断合并,向根节点上传答案。

那我们要先发现一件事,对于一个点 \(x\) 的一个子树 \(y\),它不管 \(y\) 里面怎么排列,里面产生了多少个逆序对,最终排列 \(x\) 里面的每个子树的时候,看的只是 \(y\) 里面有多少个 \(0\),多少个 \(1\),是不会管里面怎么排列的。

那我们就可以对于每个子树都看它怎么排列好。我们贪心一下。

首先,对于两个子树 \(i,j\),设它们 \(0\) 的数量为 \(num0_i,num0_j\),\(1\) 的数量为 \(num1_i,num1_j\)。

那如果 \(i\) 在 \(j\) 的前面,新增逆序对的个数就是 \(num1_i\times num0_j\)。如果在后面,就是 \(num1_j\times num0_i\)。

那假设 \(i\) 放前面比 \(j\) 放前面优,那就是 \(num1_i\times num0_j < num1_j\times num0_i\)。

那这个我们可以用堆来维护。

但是这是不能直接递归来搞的,我们要把每个点都看成独立,然后想父亲的方向合并。

那其实 \(num0,num1\) 记录的其实变成了这个点所在的连通块的 \(0,1\) 个数。

那显然上面的贪心在这里还是可以的。

那我们要维护 \(0,1\) 个数,自然要用并查集。

记得要判断当前点是否被删掉,因为当合并完之后,它父亲节点要删去,我们只要看 \(num0,num1\),就可以得知是否被合并。

还有一点就是 \(1\),也就是根节点是不用再合并的,因为没有父亲。

代码

#include<queue>
#include<cstdio> using namespace std; struct Teap {
int x, num_1, num_0;
};
bool operator < (Teap x, Teap y) {//用堆将点按贪心思想排序
return 1ll * x.num_0 * y.num_1 < 1ll * x.num_1 * y.num_0;
} int n, a[200001], father[200001];
int fa[200001], num[200001][2];
long long ans;
priority_queue <Teap> q; int find(int now) {//并查集
if (father[now] == now) return now;
return father[now] = find(father[now]);
} int main() {
scanf("%d", &n);
for (int i = 2; i <= n; i++) {
scanf("%d", &fa[i]);
}
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
num[i][a[i]]++; father[i] = i;
} for (int i = 2; i <= n; i++)
q.push((Teap){i, num[i][1], num[i][0]}); while (!q.empty()) {
Teap now = q.top();
q.pop(); int x = find(now.x);
if (num[x][0] != now.num_0 || num[x][1] != now.num_1)
continue;//这个点已近被删除 int y = find(fa[x]);
ans += 1ll * num[x][0] * num[y][1];//加上逆序对个数 num[y][0] += num[x][0];//这个子树所包含的0/1的个数增加
num[y][1] += num[x][1]; father[x] = y;//并查集连接 if (y != 1)//继续下去
q.push((Teap){y, num[y][1], num[y][0]});
} printf("%lld", ans); return 0;
}

【luogu AT3957】[AGC023F] 01 on Tree的更多相关文章

  1. 【Luogu P2515】软件安装

    Luogu P2515 这道题的题面与P2146有点像.一些不同地方就是P2146是无环的,这题是有环的. 很显然,如果有几个软件的依赖关系形成环,那么这几个软件就可以被看成是一个大软件,其价值和空间 ...

  2. 【Luogu 3275】[SCOI2011]糖果

    Luogu P3275 显然是一道经典的差分约束系统 相关知识可以查看:[Luogu 1993]差分约束系统问题--小K的农场 值得注意的是这题使用最长路更合适,因为每一个人都要取得至少一个糖果.在添 ...

  3. 【Luogu P3388】割点模板

    Luogu P3388 在一个无向图中,如果有一个顶点集合,删除这个顶点集合以及这个集合中所有顶点相关联的边以后,图的连通分量增多,就称这个点集为割点集合. 如果某个割点集合只含有一个顶点X(也即{X ...

  4. 【Luogu P1164】小A点菜

    题目原链接: Luogu 小A点菜 [解题思路] 常规的0-1背包,不过是求装满整个背包的方案数,只要把0-1背包的状态转移方程稍微改一下就行.因为要求方案数,那么把方程中的max换成sum就行. [ ...

  5. 【30.36%】【codeforces 740D】Alyona and a tree

    time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...

  6. 【Luogu P1981】表达式求值

    点我进入原题Luogu P1981 [解题思路] 仔细分析题目,这就是一道模拟题…… 直接按照符号读入全部的数字,先算乘法,最后把全部数加起来就是结果了 记得要%10000取最后四位 [参考程序] # ...

  7. 【Luogu P2563】【集训Day 4 动态规划】质数和分解

    题目链接:Luogu P2563 质数和分解(prime) [问题描述] 任何大于 1 的自然数 N,都可以写成若干个大于等于2且小于等于 N 的质数之和表达式(包括只有一个数构成的和表达式的情况), ...

  8. 【Luogu P1090】合并果子

    Luogu P1090 [解题思路] 刚看到这题的时候,第一反应就是每次取两个最小,然后重新排序,再取最小.但是这样会TLE. 既然找最小的,那就可以利用单调队列了.显然输入的数据是不具有单调性的,但 ...

  9. 【POJ 2823】【Luogu P1886】Sliding Window 滑动窗口

    POJ 2823 Luogu P1886 [解题思路] 这是一个单调队列算法的经典题目,几乎学习单调队列的人都接触过这题. 利用单调队列算法求出每一个固定区间内的最(大/小)值. 以下以最大值为例: ...

随机推荐

  1. 【Oracle】userenv()函数介绍分析

    说到这个userenv()使用起来还是很有用的 参数   功能 CLINET_INFO                                      返回最高可达64个字节存储的用户会话信 ...

  2. Log4j日志记录

    1.导入log4j的jar包 2.写log4j.properties文件,配置日志记录参数,一般参数如下所示: 第二行指定了输出日志的目录,此处用的相对路径,也可换成绝对路径: 第三行指定了输出的记录 ...

  3. LeetCode965. 单值二叉树

    题目 1 class Solution { 2 public: 3 int flag = 0; 4 bool isUnivalTree(TreeNode* root){ 5 isUnivalTree1 ...

  4. RCE - Pikachu

    概述: 远程系统命令执行 一般出现这种漏洞,是因为应用系统从设计上需要给用户提供指定的远程命令操作的接口 比如我们常见的路由器.防火墙.入侵检测等设备的web管理界面上 一般会给用户提供一个ping操 ...

  5. 【葵花宝典】一天掌握Kubernetes

    1.kubernetes介绍 kubernetes,简称K8s,是用8代替8个字符"ubernete"而成的缩写.是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kuber ...

  6. Hadoop 专栏 - MapReduce 入门

    MapReduce的基本思想 先举一个简单的例子: 打个比方我们有三个人斗地主, 要数数牌够不够, 一种最简单的方法可以找一个人数数是不是有54张(传统单机计算); 还可以三个人各分一摞牌数各自的(M ...

  7. SAP 修改表和表中数据

    平时修改表中数据的方式有一下几种: 1.一般就是通过SE11或者是SE16进去,找到那条记录,然后将模式变成EDIT,然后修改保存. 2.通过SQL语句在程序中实现数据库表的修改操作 3.通过SE16 ...

  8. 基于go-cqhttp实现QQ机器人

    本篇文章记录一下自己在编写QQ机器人的时候所遇到的一些问题和核心功能的实现. QQ机器人RabbitBot采用python编写,由于是个人学习使用,故目前不会开源完整代码,只会放出核心代码供学习参考. ...

  9. 接口 Interfaces

    Interfaces - zope.interface 5.0.2.dev0 documentation https://zopeinterface.readthedocs.io/en/latest/ ...

  10. (007)每日SQL学习:将字符和数字分离

    with aa as ( select 'sad10' as data from dual union all select 'datf20' as data from dual union all ...