题目链接: http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1307

题意: 中文题诶~

思路:

解法1:暴力树剖

用一个数组 num[i] 维护编号为 i 的边当前最大能承受的重量. 在加边的过程中根据给出的父亲节点将当前边所在的链上所有边的num都减去当前加的边的重量, 注意当前边也要减自重. 那么当num首次出现负数时加的边号即位答案;

事实上这个算法的时间复杂度是O(n^2)的, 不过本题并没有出那种退化成单链的数据, 所以直接暴力也能水过;

代码:

 1 #include <iostream>
 2 #include <stdio.h>
 3 using namespace std;
 4
 5 const int MAXN = 5e4 + 10;
 6 struct node{
 7     int c, w, pre;
 8 }gel[MAXN];
 9 int num[MAXN];//num[i]为编号为i的绳子当前可以承受的最大重量
10
11 int main(void){
12     int n, ans = -1;
13     scanf("%d", &n);
14     for(int i = 0; i < n; i++){
15         scanf("%d%d%d", &gel[i].c, &gel[i].w, &gel[i].pre);
16         if(ans != -1) continue;
17         num[i] = gel[i].c;
18         int cnt = i;
19         while(cnt != -1){
20             num[cnt] -= gel[i].w;
21             if(ans == -1 && num[cnt] <= -1) ans = i;
22             cnt = gel[cnt].pre;//指向cnt的父亲节点
23         }
24     }
25     if(ans == -1) cout << n << endl;
26     else cout << ans << endl;
27     return 0;
28 }

View Code

解法2: 二分 + dfs

很显然在加边的过程中所有边的承受重量都是单调不减的, 那么可以考虑二分答案. 不过要注意判断函数的写法, 每一次判断都需要判断当前 mid条 边组成的树的所有边, 而不能只判断当前 mid 所在链上的边, 显然其他链上也可能存在不合法的边. 判断所有边的话可以 dfs 一遍, 回溯时判断即可.

代码:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <vector>
 4 #define ll long long
 5 using namespace std;
 6
 7 const int MAXN = 5e4 + 10;
 8 struct node{
 9     int c, w, pre;
10 }gel[MAXN];
11 vector<int> sol[MAXN];
12 bool flag;
13
14 ll dfs(int u, int x){
15     ll sum = gel[u].w;
16     if(u > x) return 0;//mid边后面的不要算上去
17     for(int i = 0; i < sol[u].size(); i++){
18         sum += dfs(sol[u][i], x);
19     }
20     if(sum > gel[u].c && u) flag = false;//0是一个虚根,并没有对应的边
21     return sum;
22 }
23
24 int main(void){
25     int n;
26     scanf("%d", &n);
27     for(int i = 1; i <= n; i++){
28         scanf("%d%d%d", &gel[i].c, &gel[i].w, &gel[i].pre);
29         gel[i].pre++;
30         sol[gel[i].pre].push_back(i);
31     }
32     int l = 1, r = n, cnt = n;
33     while(l <= r){
34         flag = true;
35         int mid = (l + r) >> 1;
36         dfs(0, mid);
37         if(flag) cnt = mid, l = mid + 1;
38         else r = mid - 1;
39     }
40     printf("%d\n", cnt);
41 }

View Code

解法3: 并查集

记录每个节点的父节点
然后按输入顺序的倒叙 遍历每一个节点
计算以当前节点为根的子树的重量 ( 因为按照题目的输入顺序来说  当前节点要么没有子节点  要么子树已经遍历完 算入当前树的重量)
当遍历到某个节点时
当前节点与父节点的边无法承载当前节点为根的子树  便从输入序列最晚输入的节点开始删除 
直到与父节点的边的能够承载当前节点为根的子树
又或者已经把遍历过的点都删除完了 
这个过程中  用并查集维护某个节点 属于那一个跟节点 并且不断的压缩路径
每个条路径被压缩一次 均摊时间 就是边的数量 所以 这种做法很稳定的 O(n)
上面这段话是直接从讨论中复制过来的
代码:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <vector>
 4 #define ll long long
 5 using namespace std;
 6
 7 const int MAXN = 1e5 + 10;
 8 struct node{
 9     ll c, w, p;
10 }gel[MAXN];
11
12 ll ww[MAXN];
13 vector<int> vt[MAXN];
14 int pre[MAXN], sol;
15
16 int find(int x){
17     return pre[x] == x ? x : pre[x] = find(pre[x]);
18 }
19
20 void update(int u){
21     for(int i = 0; i < vt[u].size(); i++){
22         gel[u].w += gel[vt[u][i]].w;
23         pre[vt[u][i]] = u;
24     }
25     while(gel[u].w > gel[u].c){//u即为当前根节点
26         gel[find(sol)].w -= ww[sol];
27         sol--;
28     }
29 }
30
31 int main(void){
32     int n;
33     scanf("%d", &n);
34     for(int i = 1; i <= n; i++){
35         scanf("%lld%lld%lld", &gel[i].c, &gel[i].w, &gel[i].p);
36         gel[i].p++;
37         vt[gel[i].p].push_back(i);
38         ww[i] = gel[i].w;//后面会对gel操作,所以需要先记录下gel的初始值来
39         pre[i] = i;
40     }
41     sol = n;
42     for(int i = n; i > 0; i--){
43         update(i);
44     }
45     printf("%d\n", sol);
46     return 0;
47 }

View Code

转载于:https://www.cnblogs.com/geloutingyu/p/7121750.html

51nod1307(暴力树剖/二分dfs/并查集)相关推荐

  1. 51nod 1307 绳子与重物 二分+dfs / 并查集

    题目链接: http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1307 题意: 题解: 方法一: 因为所有绳子最终组成了1棵树 ...

  2. 数据结构之树的应用:并查集

    树的应用:并查集 并查集的概念: 三种基本操作: 例: 代码实现: 并查集的概念: 将所有的数据元素放在一个集合中,将集合分成若干个互不相交的子集,每一个子集对应一颗树,所有的自己组成森林. 三种基本 ...

  3. PAT甲级1021 Deepest Root :[C++题解]树的最大深度、并查集、dfs求树的深度

    文章目录 题目分析 题目链接 题目分析 分析: 考察知识点:并查集.dfs.树的深度 给定n个结点,n-1条边,只要能保证只有1个连通分量,就是一棵树.否则的话就不是树,它是不连通的. 用并查集来看是 ...

  4. XXI Open Cup. Grand Prix of Korea I. Query On A Tree 17 树剖 + 二分 + 树带权重心

    传送门 文章目录 题意: 思路: 题意: 给你一棵树,每棵树初始权值都为000,现在给你两个操作: (1)(1)(1)将uuu的子树权值全部加111. (2)(2)(2)将(u,v)(u,v)(u,v ...

  5. 线段树分治 ---- F. Extending Set of Points(线段树分治 + 可撤销并查集)

    题目链接 题目大意: 你有个点集合SSS,每次往集合里面加点或者删点(如果要加的点出现过),如果(x1,y1),(x2,y1),(x1,y2),(x2,y2)(x1,y1),(x2,y1),(x1,y ...

  6. BZOJ 2143 飞飞侠(线段树优化建边 / 并查集优化最短路)【BZOJ修复工程】

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 题目链接 https://hydro.ac/d/bzoj/p/2143 是 hydro 的 BZOJ ...

  7. 【CF813F】Bipartite Checking(线段树分治+可删除并查集)

    文章目录 title solution code title You are given an undirected graph consisting of n vertices. Initially ...

  8. Codeforces Round #548 (Div. 2) C. Edgy Trees(dfs || 并查集)

    题目链接:https://codeforces.com/contest/1139/problem/C 题意:给了一棵树,n个点,m条边.让从中选k个点,使得从a1到a2,a2到a3,ak-1到ak的路 ...

  9. BZOJ4399 魔法少女LJJ【线段树合并】【并查集】

    Description 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了 LJJ感叹道"这里真是个迷人的绿色世界,空气清新.淡雅 ...

最新文章

  1. 区块链教程Fabric1.0源代码gRPC(Fabric中注册的gRPC Service)一
  2. SqlHelper.cs 使用时要注意的地方
  3. java 隐藏文件_java-如何仅列出jtree中的非隐藏文件和非系...
  4. TypeScript 变量声明
  5. 字节跳动python面试_【字节跳动Python面试】生平遇到最好的面试体验-看准网
  6. JavaFX布局中图片在表格中无法被自适应缩小?
  7. 理解node.js(Understanding node.js)
  8. 【Flink】数据传输 挖个坑 把自己埋了 ClassCastException String cannot be cast to [LJava.lang.String
  9. 推荐12个非常不错而且免费的后台管理HTML模板
  10. mysql共享锁与排他锁
  11. 7.29~8.2 广州软件所-实习工作日记
  12. 为什么做网站一般不用服务端控件?
  13. Python爬虫Scrapy入门
  14. python实现自适应中值滤波器
  15. 使用Foxmail登录阿里企业邮箱(钉钉邮箱)
  16. 微信小程序之移动端适配
  17. linux下编译和安装log4cxx,ubuntu下log4cxx安装使用
  18. VS Code开源软件介绍——史上最优秀的 IDE ?
  19. 如何提取伴奏?1分钟让你知道伴奏提取软件手机版有哪些
  20. Codeforces 513G1 or 513G2 Inversions problem DP

热门文章

  1. HISTORY OF ETHEREUM SECURITY VULNERABILITIES, HACKS AND THEIR FIXES
  2. APK加壳【3】通用内存加载dex方案分析
  3. 美团Android资源混淆保护实践
  4. sql安装目录下log文件夹_Linux安装Hive数据仓库工具
  5. homeassistant树莓派cpu_集成ESP8266的WiFi RGB灯泡接入Home Assistant
  6. c malloc 头文件_C语言提高篇_malloc,realloc和calloc的区别
  7. 关于c++静态类的说法
  8. 使用C/C++解析json文件
  9. C++的黑科技 利用一个字符对字符串进行分离
  10. 最大匹配 人员分配[邻接表]