工作安排加强版(神奇的并查集)

题目描述:

为了维持农场的运转,约翰必须打工赚钱。他接到了 N 份工作,每份工作恰好占用他一天的时间。约翰从第一天开始工作,他可以任意安排这些工作的顺序,第 i 份工作有 Pi 的报酬,但必须在第 Di 天结束之前完成。在截止日期后完成的工作没有报酬。请帮助约翰规划每天的工作,使得他赚到的钱最多。

1 ≤ N ≤ 105  , 1 ≤ Di ,Pi ≤ 109     这题就恶心在数据范围额。

解题过程:

1.这题寒假做贪心专题的时候做到过,贪心策略大致还记得,就是先按照报酬P从大到小排序,然后依次安排工作,(从Di开始往前找到第一个没有安排时间的节点)。但是看数据范围,呵呵呵呵。能过2个点。

2.一个优化:用一个father数组保存每个时间节点之前的第一个空位的位置。。  每次沿着father数组找到第一个空位。 然后高兴地提交了一下,还是2个点。。

3.专题名字是“并查集”,就尽量往并查集的方向想了。发现2中“每次沿着father数组找到第一个空位”的过程其实就是并查集的get_father。。那么就可以用并查集来写。当一个位置t已经被占用了,那么就merge(t-1,t)。 (注意要按顺序,必须是t所在集合连到t-1所在集合下面)。 然后又激动的提交了一下,还是2个点。。

4. 再次看了眼数据范围, 1 ≤ Di ,Pi ≤ 109        妈蛋还以为 Di的范围和N是一样的。。  那么father数组根本没法开到那么大。。。

5. 感觉思路应该是对的,所以尽量加些优化。。然后就想到可以根据Di离散化,按先Di排一下序,把Di,然后用 一个d[i]表示Di-Di-1  。 (去掉重复的点),做出每个Di对应的编号。 修改一下前面的算法,每次get_father找到第一个空位k,然后d[k]--,如果d[k]==0 ,就merge(k-1,k);   实践证明此方法可行。。 神奇的并查集。

时间: 2025-01-19 20:48:38

工作安排加强版(神奇的并查集)的相关文章

BZOJ 3562: [SHOI2014]神奇化合物 并查集+dfs

点击打开链接 注意到20w条边,但是询问只有1w,所以有很多边是从头到尾不变的. 首先离线处理,将从未删除的边缩点,缩点后的图的点数不会超过2w,对于每一次add或者delete,直接dfs看是否能从a走到b,然后维护一个ans. 数据不强,不然这种复杂度起码要跑10s.. #include<stdio.h> #include<iostream> #include<algorithm> #include<cstring> using namespace st

【BZOJ2594】水管局长加强版,LCT+并查集+二分查找位置

Time:2016.05.10 Author:xiaoyimi 转载注明出处谢谢 传送门 思路: LCT维护路径最小值 倒叙处理询问,就相当于往图里面加边. 实时维护最小值,即最小生成树,可以参照魔法森林. 最初的最小生成树操作用kruskal 最蛋疼的是处理询问时你不知道要删除哪条边,这给kruskal带来很大麻烦,所以我们对原来的每一条边使其编号小的端点在前,大的在后,然后以左端点为第一关键字,右端点为第二关键字排序,记录下每个左端点的所在区间,然后就可以通过二分查找的方式来确定是哪条边了

BZOJ 3674 可持久化并查集加强版 可持久化并查集

题目大意:同3673 强制在线 同3673 仅仅只是慢了一些0.0 这道题仅仅写路径压缩比仅仅写启示式合并要快一点点 两个都写就慢的要死0.0 改代码RE的可能是内存不够 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 200200 using namespace std; struct Tree{ Tree *ls,*rs; int nu

一道神奇的并查集

#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; template<class T> inline void read(T &_a){ bool f=0;int _ch=getchar();_a=0; while(_ch<'0' || _ch>'9'){if(_ch=='-')f=1;_ch=g

[BZOJ1854][Scoi2010]游戏(二分图匹配/并查集)

题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1854 分析:很裸的一道二分图匹配对吧,但是在hzwer的blog上看见神奇的并查集做法! 其实这题和bzoj1191惊人的相似! 把权值当作点,装备当作边,既然一个装备只能选择一个属性,也就是你要人为给边定向,箭头指到的点就表示你这个装备选的属性. 然后就和bzoj1191一样的了 如果一个集合里的点构成一个树,那么很显然,把那个权值最大的点作为根,除了根节点以外的点都可以选出,如果

zoj 3659 第37届ACM/ICPC 长春赛区现场赛E题 (并查集)

题意:给出一棵树,找出一个点,求出所有点到这个点的权值和最大,权值为路径上所有边权的最小值. 用神奇的并查集,把路按照权值从大到小排序,然后用类似Kruskal的方法不断的加入边. 对于要加入的一条路,这条路连接这城市x和y,x所在的集合为A, y所在的集合为B, 可以确定A,B集合内的所有路都比当前这条路的权值大.如果让集合B加入集合A,就是让中心城市位于集合A,那么可以确定这两个集合合并之后的总权值为: A的权值总和+B的数量*当前这条路的权值.同样算出让集合B加入集合A的情况,取两者合并后

经典算法题每日演练——第十五题 并查集

原文:经典算法题每日演练--第十五题 并查集 这一篇我们看看经典又神奇的并查集,顾名思义就是并起来查,可用于处理一些不相交集合的秒杀. 一:场景 有时候我们会遇到这样的场景,比如:M={1,4,6,8},N={2,4,5,7},我的需求就是判断{1,2}是否属于同一个集合,当然实现方法 有很多,一般情况下,普通青年会做出O(MN)的复杂度,那么有没有更轻量级的复杂度呢?嘿嘿,并查集就是用来解决这个问题的. 二:操作 从名字可以出来,并查集其实只有两种操作,并(Union)和查(Find),并查集

TYVJ并查集

神奇的并查集 P1017 冗余关系 当年刚刚学会并查集,合并写的是rank(),ce了好多次 #include <cstdio> int father[5001]; int m,n,c,d,a; int find(int a){ return (father[a]==a) ? a : (father[a]=find(father[a])); } int main(){ scanf("%d%d",&n,&m); for (int i=1;i<=m;i++

可持久化并查集加强版 BZOJ 3674

http://www.lydsy.com/JudgeOnline/problem.php?id=3674 3674: 可持久化并查集加强版 Time Limit: 15 Sec  Memory Limit: 256 MBSubmit: 3225  Solved: 1192[Submit][Status][Discuss] Description Description:自从zkysb出了可持久化并查集后--hzwer:乱写能AC,暴力踩标程KuribohG:我不路径压缩就过了!ndsf:暴力就可