51nod1307(暴力树剖/二分&dfs/并查集)
题目链接: http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1307
题意: 中文题诶~
思路:
解法1:暴力树剖
用一个数组 num[i] 维护编号为 i 的边当前最大能承受的重量. 在加边的过程中根据给出的父亲节点将当前边所在的链上所有边的num都减去当前加的边的重量, 注意当前边也要减自重. 那么当num首次出现负数时加的边号即位答案;
事实上这个算法的时间复杂度是O(n^2)的, 不过本题并没有出那种退化成单链的数据, 所以直接暴力也能水过;
代码:
#include <iostream>
#include <stdio.h>
using namespace std; const int MAXN = 5e4 + ;
struct node{
int c, w, pre;
}gel[MAXN];
int num[MAXN];//num[i]为编号为i的绳子当前可以承受的最大重量 int main(void){
int n, ans = -;
scanf("%d", &n);
for(int i = ; i < n; i++){
scanf("%d%d%d", &gel[i].c, &gel[i].w, &gel[i].pre);
if(ans != -) continue;
num[i] = gel[i].c;
int cnt = i;
while(cnt != -){
num[cnt] -= gel[i].w;
if(ans == - && num[cnt] <= -) ans = i;
cnt = gel[cnt].pre;//指向cnt的父亲节点
}
}
if(ans == -) cout << n << endl;
else cout << ans << endl;
return ;
}
解法2: 二分 + dfs
很显然在加边的过程中所有边的承受重量都是单调不减的, 那么可以考虑二分答案. 不过要注意判断函数的写法, 每一次判断都需要判断当前 mid条 边组成的树的所有边, 而不能只判断当前 mid 所在链上的边, 显然其他链上也可能存在不合法的边. 判断所有边的话可以 dfs 一遍, 回溯时判断即可.
代码:
#include <iostream>
#include <stdio.h>
#include <vector>
#define ll long long
using namespace std; const int MAXN = 5e4 + ;
struct node{
int c, w, pre;
}gel[MAXN];
vector<int> sol[MAXN];
bool flag; ll dfs(int u, int x){
ll sum = gel[u].w;
if(u > x) return ;//mid边后面的不要算上去
for(int i = ; i < sol[u].size(); i++){
sum += dfs(sol[u][i], x);
}
if(sum > gel[u].c && u) flag = false;//0是一个虚根,并没有对应的边
return sum;
} int main(void){
int n;
scanf("%d", &n);
for(int i = ; i <= n; i++){
scanf("%d%d%d", &gel[i].c, &gel[i].w, &gel[i].pre);
gel[i].pre++;
sol[gel[i].pre].push_back(i);
}
int l = , r = n, cnt = n;
while(l <= r){
flag = true;
int mid = (l + r) >> ;
dfs(, mid);
if(flag) cnt = mid, l = mid + ;
else r = mid - ;
}
printf("%d\n", cnt);
}
解法3: 并查集
#include <iostream>
#include <stdio.h>
#include <vector>
#define ll long long
using namespace std; const int MAXN = 1e5 + ;
struct node{
ll c, w, p;
}gel[MAXN]; ll ww[MAXN];
vector<int> vt[MAXN];
int pre[MAXN], sol; int find(int x){
return pre[x] == x ? x : pre[x] = find(pre[x]);
} void update(int u){
for(int i = ; i < vt[u].size(); i++){
gel[u].w += gel[vt[u][i]].w;
pre[vt[u][i]] = u;
}
while(gel[u].w > gel[u].c){//u即为当前根节点
gel[find(sol)].w -= ww[sol];
sol--;
}
} int main(void){
int n;
scanf("%d", &n);
for(int i = ; i <= n; i++){
scanf("%lld%lld%lld", &gel[i].c, &gel[i].w, &gel[i].p);
gel[i].p++;
vt[gel[i].p].push_back(i);
ww[i] = gel[i].w;//后面会对gel操作,所以需要先记录下gel的初始值来
pre[i] = i;
}
sol = n;
for(int i = n; i > ; i--){
update(i);
}
printf("%d\n", sol);
return ;
}
51nod1307(暴力树剖/二分&dfs/并查集)的更多相关文章
- 【CF576E】Painting Edges 线段树按时间分治+并查集
[CF576E]Painting Edges 题意:给你一张n个点,m条边的无向图,每条边是k种颜色中的一种,满足所有颜色相同的边内部形成一个二分图.有q个询问,每次询问给出a,b代表将编号为a的边染 ...
- BZOJ_4025_二分图_线段树按时间分治+并查集
BZOJ_4025_二分图_线段树按时间分治+并查集 Description 神犇有一个n个节点的图.因为神犇是神犇,所以在T时间内一些边会出现后消失.神犇要求出每一时间段内这个图是否是二分图.这么简 ...
- 【BZOJ1821】[JSOI2010]部落划分(二分,并查集)
[BZOJ1821][JSOI2010]部落划分(二分,并查集) 题面 BZOJ 洛谷 题解 二分答案,把距离小于二分值的点全部并起来,\(\mbox{check}\)一下是否有超过\(K\)个集合就 ...
- 洛谷P4145 上帝造题的七分钟2/花神游历各国 [树状数组,并查集]
题目传送门 题目背景 XLk觉得<上帝造题的七分钟>不太过瘾,于是有了第二部. 题目描述 "第一分钟,X说,要有数列,于是便给定了一个正整数数列. 第二分钟,L说,要能修改,于是 ...
- 【bzoj3007】拯救小云公主 二分+对偶图+并查集
题目描述 英雄又即将踏上拯救公主的道路…… 这次的拯救目标是——爱和正义的小云公主. 英雄来到boss的洞穴门口,他一下子就懵了,因为面前不只是一只boss,而是上千只boss.当英雄意识到自己还是等 ...
- [HNOI2006]公路修建问题 (二分答案,并查集)
题目链接 Solution 二分答案+并查集. 由于考虑到是要求花费的最小值,直接考虑到二分. 然后对于每一个二分出来的答案,模拟 \(Kruskal\) 的过程再做一遍连边. 同时用并查集维护联通块 ...
- BZOJ 4034 [HAOI2015]树上操作 线段树+树剖或dfs
题意 直接照搬原题面 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所 ...
- CF 115 A 【求树最大深度/DFS/并查集】
CF A. Party time limit per test3 seconds memory limit per test256 megabytes inputstandard input outp ...
- hdu 5652 India and China Origins(二分+bfs || 并查集)BestCoder Round #77 (div.2)
题意: 给一个n*m的矩阵作为地图,0为通路,1为阻碍.只能向上下左右四个方向走.每一年会在一个通路上长出一个阻碍,求第几年最上面一行与最下面一行会被隔开. 输入: 首行一个整数t,表示共有t组数据. ...
随机推荐
- 代码题(3)— 最小的k个数、数组中的第K个最大元素、前K个高频元素
1.题目:输入n个整数,找出其中最小的K个数. 例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4. 快排思路(掌握): class Solution { public ...
- Linux基本语法
Shell编程 摘要: Shell历史 Shell的作用是解释用户的命令,用户输入一条命令,Shell就解释执行一条,这条方式称为交互式(interactive),Shell还有一种执行命令的方式称为 ...
- linux命令学习笔记(38):cal 命令
cal命令可以用来显示公历(阳历)日历.公历是现在国际通用的历法,又称格列历,通称阳历. “阳历”又名“太阳历”,系以地球绕行太阳一周为一年,为西方各国所通用,故又名“西历”. .命令格式: cal ...
- 利用Perlin nosie 完成(PS 滤镜—— 分成云彩)
%%%% Cloud %%%% 利用perlin noise生成云彩 clc; clear all; close all; addpath('E:\PhotoShop Algortihm\Image ...
- Debian for ARM install python 3.5.x
/********************************************************************************** * Debian for ARM ...
- 1068 Find More Coins (30)(30 分)
Eva loves to collect coins from all over the universe, including some other planets like Mars. One d ...
- hdu 5909 Tree Cutting —— 点分治
题目:http://acm.hdu.edu.cn/showproblem.php?pid=5909 点分治,每次的 rt 是必选的点: 考虑必须选根的一个连通块,可以DP,决策就是在每个子树中决定选不 ...
- bzoj 5120 无限之环 & 洛谷 P4003 —— 费用流(多路增广SPFA)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=5120 https://www.luogu.org/problemnew/show/P4003 ...
- HDOJ1024(最大M子段和)
Max Sum Plus Plus Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others ...
- HDOJ1022(模拟栈)
Train Problem I Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)T ...