分治算法

trivial分治算法

情到浓时终转凉″ 提交于 2020-02-03 02:37:15
按时间分治: CDQ分治 解决大多可以归化为 k k k 维偏序问题的离线算法。 K K K 维偏序问题的 b i t s e t bitset b i t s e t 解法: [已完成]例题1:CF 70 D ,支持动态加点的凸包问题,可以使用CDQ分治变成离线. [已完成]例题2:CF 848C, 设一段区间的价值为区间内每个出现过的数,最后一次出现的位置-第一次出现的位置之和。要求支持单点修改和区间查询。 解法:把每个 ai 看作二元组 ( i , p r e v a i ) (i,prev_{a_i}) ( i , p r e v a i ​ ​ ) ,则 a i a_i a i ​ 在区间内的贡献为 ∑ l ≤ i , p r e v a i ≤ r i − p r e v a i \sum_{l≤i,prev_{a_i}≤r}i−prev_{a_i} ∑ l ≤ i , p r e v a i ​ ​ ≤ r ​ i − p r e v a i ​ ​ ,中间的部分均消去,剩余的贡献恰为题目所求。因此,时间、 i i i 、 p r e v a i prev_{a_i} p r e v a i ​ ​ 组成了三维数点问题的三个维度,套用 CDQ 分治解决。 例题3:【UOJ#50】【UR #3】链式反应(分治FFT,动态规划) 线段树分治 动态图连通性.

算法之分治学习(快速排序)

馋奶兔 提交于 2020-02-02 03:07:30
整体思路 分支步骤:分解问题 (1)分解:将原问题分解成一系列子问题 (2)解决:递归地解各子问题。若子问题足够小,则直接有解; (3)合并:将子问题的结果合并成原问题的解 题目 1、快速排序 (1)题目 就是数组的快速排序啦 (2)代码 package com . lanqiao . vidio ; public class QuickSort { public static void main ( String [ ] args ) { int [ ] A = { 9 , 6 , 1 , 5 , 8 } ; sort ( A , 0 , A . length - 1 ) ; for ( int a : A ) { System . out . print ( a + " " ) ; } } public static void sort ( int [ ] A , int p , int r ) { if ( p < r ) { int q = partition ( A , p , r ) ; sort ( A , p , q - 1 ) ; sort ( A , q + 1 , r ) ; } } private static int partition ( int [ ] A , int p , int r ) { int pivot = A [ p ] ; int sp

NOI图论大全

泪湿孤枕 提交于 2020-02-01 22:34:07
前言   本文诣在实现NOI图论的全覆盖,各知识点以提纲的形式出现,未涉及具体原理及实现,但附有优质的讲解blog的网址,用于有一定算法基础的同学复习、巩固、加深。 Part1:点分治 & 点分树 一 . 点分治概述 点分治是一种在树上比较常用的分治方法,适用于一些树上的数据结构类问题。 算法大致流程: 求出当前部分树的重心 计算与当前重心相关的答案,如:经过该重心的路径条数、长度等。 删除重心,将当前部分树分成更多部分,重复上述操作。 代码 主要用处:处理路径信息,因为: 每次以重心分割树,可以处理经过当前重心的路径 每次处理的路径不重复、不疏漏 将路径分为不相干的两段,方便数据结构处理。 复杂度:O(nlogn + ∑ 单次处理关于重心答案)。 点分治讲解blog 二 . 点分树概述 定义:使结点x与所在部分树中的重心y连边,所得到的树形结构叫做点分树。 求点分树的方法就是在 divide(rt) 前加一句 add_edge(x,rt) 即可。 主要用处:让点分治实现修改操作。 复杂度:同点分治复杂度。 三 . 例题选讲     T1. [CF293E]Close Vertices     大部分点分治的唯一问题:如何计算经过重心x的合法路径条数。方法如下: 计算该部分树中每个结点到重心的距离及边权和,可通过一遍DFS实现。 计算两两路径配对所得的合法路径条数:将结点按长度排序

点分治

佐手、 提交于 2020-01-26 10:15:57
Purpose 利用 \(nlogn\) 的时间复杂度巧妙地处理出很多树上路径统计问题。 Solve 我们如果选定一个点作为整棵树的根,那么树上的路径必定可以大致区分为以下两种: 经过根节点的 不经过根节点的 那么,我们只处理第一种路径,对于第二种,对于它经过的每个点,如果以这些点中的一个作为根节点,那么相对于这些点为根的时候,第二种路径肯定迟早会被处理。 而点分治的做法,则是选定一个点作为根节点,先统计所有经过此点的路径,然后分别递归下去处理它的每颗子树,在每颗子树中选出根节点,然后统计子树中经过子树根节点的路径,再递归处理子树根节点的子树。 那么直到处理的子树大小为 \(1\) 的时候,就到达了边界。 以上就是分治过程。 那么具体怎么做呢?我们分步骤考虑: 处理经过当前根节点的路径。 首先,如果一条路径经过当前根节点,那么它的两端必定在根节点的两个 不同 的子树中。 我们先一个个子树地统计每条路径到根节点的情况并记录下来,对于当前子树,我们统计完路径情况之后先不急着存入总情况内,由于总情况已经存入了前面访问过的所有子树,我们先将当前子树内所有情况与当前总情况一一配对,再将当前子树统计信息存入总情况内即可做到每颗子树内的配对无遗漏。 递归处理 对于根节点的每颗子树我们都要通过递归往下处理,但是每次的根节点怎么选择呢?难道乱选不成? 我们首先观察一下整个算法,我们发现

分治之求逆序对数

好久不见. 提交于 2020-01-25 01:18:44
分治求逆序对数 用分治求逆序对数,其思想与归并排序差不多,具体的我们可以看一下伪代码 第一步还是把一个大的数组进行分割,直至不能再分为止,这样的话总的逆序对数就可以分为三部分,左边数组的逆序对数、右边数组的逆序对数、左右数组交叉形成的逆序数对数。所以最后的结果是把他们三个加起来。第一步的伪代码: Count_Sort ( A ) Divide A into two sub_array L and R Lc = Count_Sort ( L ) Rc = Count_Sort ( R ) LR = Merge_Count ( L , R ) return Lc + Rc + LR 第二部就是比较复杂的一步,类比归并排序,也是两个指针分别从左右两个数组中取元素进行比较,但是比暴力计算逆序对数去掉了很多冗余,因为左右数组都排好序的情况下,如果左边数组的一个元素a比右边数组的一个元素b大的话,那么在左边数组中,a后边的所有元素都要比b大,所以a后面的元素就不用和b再进行比较了。伪代码: Merge_Count ( L , R ) num = 0 , i = 0 , j = 0 for k = 0 to || L || + || R || - 1 do if L [ i ] > R [ j ] A [ k ] = R [ j ] j ++ num + = ( || L || - i )

知识点二十:分治算法

我们两清 提交于 2020-01-24 17:47:34
前言 MapReduce 是 Google 大数据处理的三驾马车之一,另外两个是 GFS 和 Bigtable。MapReduce在倒排索引、PageRank 计算、网页分析等搜索引擎相关的技术中都有大量的应用。尽管开发一个 MapReduce 看起来很高深,感觉跟我们遥不可及。实际上,万变不离其宗,它的本质就是 分治算法 。 如何理解分治算法? 分治算法(divide and conquer)的核心思想其实就四个字: 分而治之 ,也就是 将原问题划分成 n 个规模较小,并且结构与原问题相似的子问题,递归地解决这些子问题,然后再合并其结果,就得到原问题的解 。这个定义看起来有点类似递归的定义。关于分治和递归的区别,我们只要记住一点, 分治算法是一种处理问题的思想,而递归是一种编程技巧 。实际上,分治算法一般都比较适合用递归来实现。分治算法的递归实现中,每一层递归都会涉及这样三个操作: 分解:将原问题分解成一系列子问题; 解决:递归地求解各个子问题,若子问题足够小,则直接求解; 合并:将子问题的结果合并成原问题。 分治算法能解决的问题,一般需要满足下面这几个条件: 原问题与分解成的小问题具有相同的模式; 原问题分解成的子问题可以独立求解, 子问题之间没有相关性 ,这一点是分治算法跟动态规划的明显区别; 具有分解终止条件,也就是说,当问题足够小时,可以直接求解;

【排序】归并类排序—归并排序(逆序数问题)

血红的双手。 提交于 2020-01-23 23:21:13
文章目录 前言 归并排序(merge sort) 逆序数 结语 微信公众号: bigsai 数据结构与算法专栏 前言 在排序中,我们可能大部分更熟悉冒泡排序、快排之类。对归并排序可能比较陌生。然而事实上归并排序也是一种稳定的排序,时间复杂度为O(nlogn). 归并排序是基于分治进行归并的,有 二路归并 和多路归并.我们这里只讲二路归并并且日常用的基本是二路归并。并且 归并排序的实现方式 有 递归形式 和 非递归形式 。要注意其中的区分(思想上没有大的区别,只是划分上会有区分后面会对比)。 并且归并排序很重要的一个应用是求序列中的逆序数个数。当然 逆序数也可以用树状数组 完成,这里就不介绍了。 归并排序(merge sort) 归并和快排都是 基于分治算法 的。分治算法其实应用挺多的,很多分治会用到递归,也有很多递归实现的算法是分治,但事实上 分治和递归是两把事 。分治就是分而治之。因为面对排序,如果不采用合理策略。每多一个数就会对整个整体带来巨大的影响。而分治就是将整个问题可以分解成相似的子问题。子问题的解决要远远高效于整个问题的解决,并且子问题的合并并不占用太大资源。 至于归并的思想是这样的: 第一次:整串先进行划分成1个一个单独,第一次是一一( 12 34 56--- )归并成若干对,分成若干2个区间.归并完( xx xx xx xx---- )这样局部有序的序列。

Java数据结构与算法精讲

被刻印的时光 ゝ 提交于 2020-01-23 03:19:40
课程简介 本系列视频教程为数据结构与算法基础,使用java语言描述,适合没有学过C/C++有一定Java基础的同学。没有Java基础的同学可以先行学习Java基础。 课程目录 ├─线性表 ├─栈和队列 ├─HashMap和LinkedHashMap ├─树 ├─二叉树 ├─图 ├─图的遍历与最小生成树 ├─图的最短路径与拓扑排序 ├─算法简介 ├─算法排序 ├─排序与归并 ├─递归与穷举 ├─贪心和分治 ├─动态规划和回溯 来源: CSDN 作者: di_pingxian 链接: https://blog.csdn.net/di_pingxian/article/details/103897423

bzoj 泛做

爱⌒轻易说出口 提交于 2020-01-22 23:47:10
3003 这个题是这样的,对序列差分后,每个取反操作就是给两个端点的值取反,然后背包之后再状压就好了 4128 这题棒棒的QAQBSGS 23333 4176 这个杜教筛呃呃呃 大爷链接 3028 我要去学学生成函数 大爷链接 4025 我真TM是智商爆降了,这个东西明显的按时间分治一下就好了,管他什么lct 3498 一位大爷:“将所有点分成两类:度数 < sqrt(m)的和度数 > sqrt(m)的.先求包含第一类点的三元环个数.由于边很少,所以枚举2条边即可.由于一个点的度不超过sqrt(m),所以一条边最多被枚到(sqrt(m))次,最多枚M条边,所以这个操作时O(m sqrt(m))的.再求不包含第一类点的三元环个数.由于每条边贡献2个度,所以二类点的数量是O(sqrt(m))级的.直接枚举三个点,复杂度O((sqrt(m))^3)=O(m sqrt(m))所以算法总的复杂度是O(m*sqrt(m))的.” 5043 先发个 神犇友链 当时只知道暴力,f[i][j]表示第i位剩余j最小的k但是这样j为2^60太大无法忍受,所以可以倒着按位做表示这一位剩余j,一定满足j<=n,这样复杂度降为60n,好棒棒呦 4241 一样看以为莫队结果被怼啦 大爷链接 ,填填坑 2400 这题其实很简单,然而......因为是异或运算,所以每一位独立然后就是最小割了(捂脸 4036

BZOJ 2716 天使玩偶 CDQ分治

删除回忆录丶 提交于 2020-01-19 22:30:55
题意: 输入: 输出: 样例较长这里省略 思路: 算法:CDQ分治+树状数组 首先,题目中存在绝对值, 肯定是去掉比较容易 ,所以第一种情况是考虑分类讨论,即将查询的点当做原点,然后分四个象限分别拆绝对值,但这个时候会发现其实每个象限的算法区别不大,因此另一种想法就是每次都将所有的转到第三象限中,即通过加减转换,此时对于需要查询的 \(A\) 点,玩偶的位置 \(B\) 到达的距离都可以直接变为 \(dis=A_x+A_y-(B_x+B_y)\) 由于 \(A_x+A_y\) 的值是固定的,需要dis最小,所以我们要找到 \(B_y+B_x\) 最大的点。 由于我们直接设定的是在第三个象限,所以找到 \(B\) 点存在限制 \(B_y<=A_y\) 和 \(B_x<A_x\) 再加上一个时间限制,就是一个偏序问题。下面的思路是:先按照时间排序,在对 \(x\) 进行分治,用树状数组维护y的值。 因为这题数据很卡,下面是几个 优化 : 1、对于时间排序,每一次sort的复杂度是 \(O(nlogn)\) 一共要进行四次,那么复杂度就直接炸了,但是实际上我们可以记下最开始的排列, 每一次更改变换直接用最开始的排列。 for(int i=1; i<=tot; i++)ans[i]=INF,P[i]=a[i];//这里的P数组就是用来记录初始序列 CDQ(1,tot); for(int i