题目链接

题目

题目描述

Q国的监察院是一个神秘的组织。

这个组织掌握了整个帝国的地下力量,监察着Q国的每一个人。

监察院一共有N个成员,每一个成员都有且仅有1个直接上司,而他只听从其上直接司的命令。其中1号成员是监察院的院长,这个庞然大物的主人。

由于时代的进步,监察院议会决定升级组织的旧式通信器,安装最新的反侦测通信器。

他们拿出了M组线路方案,其中第i组线路方案可以用一个四元组(x[i]、y[i]、k[i]、w[i])描述,表示第x[i]号成员可以安装与y[i]号成员的直接通信线路,费用为w[i];x[i]号成员的上司可以安装与y[i]号成员的上司的直接通信线路,费用为w[i];x[i]号成员的上司的上司可以安装与y[i]号成员的上司的上司的直接通信线路,费用为w[i]; …… ;x[i]号成员的k[i] - 1级上司可以安装与y[i]号成员的k[i] - 1级上司的直接通信线路,费用为w[i]。(这k[i]条线路的费用独立计算)

如果一个集合内部的成员两两之间都可以通过直接或间接的通信线路进行通信,那么这个集合的所有成员可以成立一个特别行动组。

监察院想成立一个成员最多的特别行动组,同时他们想让安装线路的费用之和最小,

所以他们找到了Q国的天命者——你,请你帮助他们规划出最优的线路。

输入描述

第一行为2个正整数N、M。

第二行为N - 1个正整数L[i],第i个正整数表示第i+1个成员的直接上司L[i]。

接下来M行每行四个正整数x[i],y[i],k[i],w[i]。

输出描述

仅一行,为特别行动组成员人数的最大值和在此前提下安装线路的最小费用之和。

示例1

输入

  1. 5 3
  2. 1 1 2 2
  3. 5 4 3 10
  4. 1 3 1 5
  5. 2 4 2 3

输出

  1. 5 21

说明

设(u、v、w)表示一条u到v,费用为w的线路。

则一共有(5、4、10)、(2、2、10)、(1、1、10)、(1、3、5)、(2、4、3)、(1、2、3)共6条线路。

选择第1、4、5、6条线路,可以成立特别行动组{1、2、3、4、5},费用之和为21

备注

对于100%的数据:

1 ≤ N、M ≤ 252501

1≤x[i],y[i],k[i]≤N,1≤L[i]≤i - 1,保证x[i]、y[i]号成员均至少有k[i]个上司,\(1≤w[i]≤10^9\) 。

题解

知识点:倍增,并查集。

这题的思路非常妙,是一个按批处理的最小生成树。由于给的边都是一批一批的,一个一个处理一定超时。但是,一批边可以通过边权、起边的两个端点、上升边数唯一确定,我们可以利用这个性质一批一批处理,就能省很多时间。

具体地说,可以设 \(e_i\) 表示有 \(2^i\) 条边的若干批边,随后我们将给定的每批边细分成 \(2\) 的幂次的若干批。例如一批边有 \(11\) 条,则可以分为 \(8,2,1\) 条边的批次,将其分别放在 \(e_3,e_1,e_0\) 即可。需要注意的是,起边端点也需要随之改动,因此还需要预处理向上跳跃的倍增。

然后,按边数从大到小遍历 \(e_i\) ,对边数相同的若干批边,采用类似最小生成树的做法,筛选留下的批次。直到处理完 \(e_0\) ,留在 \(e_0\) 的边就是我们需要的,即完成了按批处理的最小生成树。

其中,对于同一边数的若干批边,我们需要选出一些批次,使得连通性不变,但边权最小,类似最小生成树。因此按批次边的权重从小到大排列,用并查集维护连通性,类似kruskal算法。最后,留下的若干批次,我们需要继续细分,排除更多的边。例如, \(e_3\) 的处理完,留下的都是 \(2^3\) 边数的批次,需要细分成 \(2^2\) 存入 \(e_2\) 继续筛选。同样地,需要注意起边端点问题。

最终我们需要统计各个最小生成树的点数和边权和,选出连通点的数量最多的情况下边权和最小的答案。

时间复杂度 \(O(\log k(n + m(\log m +\log n)) + n\log n)\)

空间复杂度 \(O(m \log k + n \log n)\)

代码

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. using ll = long long;
  4. struct Graph {
  5. struct edge {
  6. int v, nxt;
  7. };
  8. int idx;
  9. vector<int> h;
  10. vector<edge> e;
  11. Graph(int n = 0, int m = 0) { init(n, m); }
  12. void init(int n, int m) {
  13. idx = 0;
  14. h.assign(n + 1, 0);
  15. e.assign(m + 1, {});
  16. }
  17. void add(int u, int v) {
  18. e[++idx] = { v,h[u] };
  19. h[u] = idx;
  20. }
  21. };
  22. struct DSU {
  23. vector<int> fa;
  24. DSU(int n = 0) { init(n); }
  25. void init(int n) {
  26. fa.assign(n + 1, 0);
  27. iota(fa.begin(), fa.end(), 0);
  28. }
  29. int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
  30. bool same(int x, int y) { return find(x) == find(y); }
  31. void merge(int x, int y) { fa[find(x)] = find(y); }
  32. };
  33. const int N = 300000;
  34. Graph g;
  35. int f[27][N];
  36. void dfs(int u, int fa) {
  37. f[0][u] = fa;
  38. for (int i = 1;i <= 20;i++)
  39. f[i][u] = f[i - 1][f[i - 1][u]];
  40. for (int i = g.h[u];i;i = g.e[i].nxt) {
  41. int v = g.e[i].v;
  42. dfs(v, u);
  43. }
  44. }
  45. struct node {
  46. int u, v, w;
  47. friend bool operator<(const node &a, const node &b) { return a.w < b.w; }
  48. };
  49. vector<node> e[27];
  50. int main() {
  51. std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  52. int n, m;
  53. cin >> n >> m;
  54. g.init(n, n);
  55. for (int i = 2;i <= n;i++) {
  56. int u;
  57. cin >> u;
  58. g.add(u, i);
  59. }
  60. dfs(1, 0);
  61. for (int i = 1;i <= m;i++) {
  62. int u, v, k, w;
  63. cin >> u >> v >> k >> w;
  64. for (int i = 20;i >= 0;i--) {
  65. if (k & (1 << i)) {
  66. e[i].push_back({ u,v,w });
  67. u = f[i][u];
  68. v = f[i][v];
  69. }
  70. }
  71. }
  72. for (int i = 20;i >= 1;i--) {
  73. sort(e[i].begin(), e[i].end());
  74. DSU dsu(n);
  75. for (auto [u, v, w] : e[i]) {
  76. if (dsu.same(u, v)) continue;
  77. dsu.merge(u, v);
  78. e[i - 1].push_back({ u,v,w });
  79. e[i - 1].push_back({ f[i - 1][u],f[i - 1][v],w });
  80. }
  81. }
  82. sort(e[0].begin(), e[0].end());
  83. DSU dsu(n);
  84. vector<pair<int, ll>> node_ans(n + 1);
  85. for (auto [u, v, w] : e[0]) {
  86. if (dsu.same(u, v)) continue;
  87. dsu.merge(u, v);
  88. node_ans[dsu.find(u)].first++;
  89. node_ans[dsu.find(u)].second += w;
  90. }
  91. for (int i = 1;i <= n;i++) {
  92. if (dsu.find(i) != i) {
  93. node_ans[dsu.find(i)].first += node_ans[i].first;
  94. node_ans[dsu.find(i)].second += node_ans[i].second;
  95. }
  96. }
  97. vector<pair<int, ll>> ans;
  98. for (int i = 1;i <= n;i++) if (dsu.find(i) == i) ans.push_back(node_ans[i]);
  99. sort(ans.begin(), ans.end(), [&](pair<int, ll> a, pair<int, ll> b) {return a.first == b.first ? a.second < b.second : a.first>b.first;});
  100. cout << ans[0].first + 1 << ' ' << ans[0].second << '\n';
  101. return 0;
  102. }

NC14419 线路规划的更多相关文章

  1. 百度地图开发之poi检索,线路规划

      官方文档 http://lbsyun.baidu.com/index.php?title=androidsdk/guide/key 先去官方文档申请秘钥下载压缩文件等操作,参考 百度地图的秘钥申请 ...

  2. iOS调用第三方导航和线路规划

    线路规划: https://blog.csdn.net/qq_19979539/article/details/51938995 百度地图:baidumap: 高德地图:iosamap: 腾讯地图:q ...

  3. 【Wannafly挑战赛4】F 线路规划 倍增+Kruskal+归并

    [Wannafly挑战赛4]F 线路规划 题目描述 Q国的监察院是一个神秘的组织.这个组织掌握了整个帝国的地下力量,监察着Q国的每一个人.监察院一共有N个成员,每一个成员都有且仅有1个直接上司,而他只 ...

  4. [nowcoder_Wannafly挑战赛4_F]线路规划

    [nowcoder_Wannafly挑战赛4_F]线路规划 试题描述 Q国的监察院是一个神秘的组织. 这个组织掌握了整个帝国的地下力量,监察着Q国的每一个人. 监察院一共有 \(N\) 个成员,每一个 ...

  5. Wannafly #4 F 线路规划

    数据范围252501 劲啊 Q国的监察院是一个神秘的组织. 这个组织掌握了整个Q国的地下力量,监察着Q国的每一个人. 监察院一共有N个成员,每一个成员都有且仅有1个直接上司,而他只听从其上直接司的命令 ...

  6. iOS - 高德地图步行线路规划多点多条线路

    项目集成高德地图遇到的问题: 高德地图的官方步行导航只针对单个起始点单条线路,驾车导航才有途径点多线路.现在项目是要步行导航多个点多条线路

  7. 利用dijkstra算法规划线路

    # dijkstra# 1.在数据库内预先存放了北京市内最新的道路节点,选用优化了得dijkstra算法进行线路规划.    当输入起点和终点后,会计算出最短的路径.同时还能选择查看路径经过的道路节点 ...

  8. java学习规划

    今天在网上看到一位大学生的java学习线路规划,觉得蛮适合我,就详细阅读了一下,规划路线应该适用于大部分学习java语言的人,贴出来与大家共勉. 在学习的过程中,不能急于去学习更多的知识,因为知识是无 ...

  9. Android百度地图开发05之公交信息检索 + 路线规划

    在上一篇blog中介绍过POI检索的使用,本篇blog主要介绍公交信息检索和线路规划的内容. 公交信息检索 实际上,公交信息检索与POI检索.在线建议检索非常相似,也是把你需要检索的信息发送给百度地图 ...

  10. iOS百度地图路径规划和POI检索详细总结-b

    路径规划.png 百度地图的使用 百度地图API的导入网上说了许多坑,不过我遇到的比较少,这里就放两个比较常见的吧.坑一: 奥联WIFI_xcodeproj.png 如上图所示,在infoplist里 ...

随机推荐

  1. 浅谈 Docker 网络:单节点单容器

    1.Docker 网络模型 Docker 在 1.7 版本中将容器网络部分代码抽离出来作为 Docker 的网络库,叫 libnetwork.libnetwork 中使用 CNM(Container ...

  2. Redis 集群模式搭建

    本文为博主原创,未经允许不得转载: 目录: 1. 哨兵模式与集群模式对比 2. Redis 集群架构搭建 3. 集群原理分析 4. 集群元数据维护方式对比 5. redis 分布式寻址 6. 集群选举 ...

  3. Redis 主从复制架构配置及原理

    本文为博主原创,未经允许不得转载: 目录: 1. Redis 主从复制架构搭建 2. Redis 主从架构原理 3. Redis 断点续传 4. Jedis 连接 redis 主从架构一般配置一主多从 ...

  4. Asp.Net Core造轮之旅:逐步构建自己的开发框架-目录

    本系列适用于已有一定.NET开发基础,学习asp.net core人士. 基础篇 asp.net core之Startup asp.net core之依赖注入 asp.net core之中间件 asp ...

  5. 【转帖】ARM 虚拟化技术简介

    一. 虚拟化技术二. 虚拟化技术的比较2.1 全虚拟化和二进制重写(Pure virtualization and binary rewriting)2.2 半虚拟化( Para-virtualiza ...

  6. [转帖]iptables的四表五链与NAT工作原理

    本文主要介绍了iptables的基本工作原理和四表五链等基本概念以及NAT的工作原理. 1.iptables简介 我们先来看一下netfilter官网对iptables的描述: iptables is ...

  7. Python学习之十_paramiko的简单学习

    Python学习之十_paramiko的简单学习 简介 pywinrm 是python用于连接访问windows的工具 paramiko 是python用于连接访问linux的工具 ansible等工 ...

  8. ESXi规避ESXiArgs勒索软件的简单方法

    摘要 今天查看深信服科技的公众号 发现有一个ESXiArgs 的勒索软件. 感觉对公司存在一定的风险.但是感觉操作手册有点简单. 这里想着写全面一点. 作为操作手册使用. 并且深信服仅是解决了在运行, ...

  9. 使用influxdb以及Grafana监控vCenter的操作步骤

    1. 下载安装介质 计划telegraf和influxdb 使用rpm包进行安装.Grafana使用docker容器方式安装 下载路径为: https://repos.influxdata.com/r ...

  10. 使用perfdog如何测试微信小程序

    测试微信小程序和测试其他app唯一的不同点是如何在app中选中要测试的小程序 至于其他的基本操作可查看https://www.cnblogs.com/lihongtaoya/p/15140610.ht ...