莫队算法详解

合集下载

匈牙利算法基本原理

匈牙利算法基本原理

匈牙利算法(Hungarian algorithm),也称为Kuhn-Munkres算法,是用于解决最大权匹配问题的一种经典算法。

它的基本原理是通过逐步改进当前匹配来寻找最优匹配。

以下是匈牙利算法的基本原理:
1. 初始化:将每个顶点的匹配状态设置为未匹配。

创建一个大小为n×n的矩阵,其中n是顶点数目。

矩阵表示图中边的权重。

2. 第一阶段:对于每个未匹配的顶点,尝试为其寻找匹配。

从该顶点开始进行深度优先搜索(DFS)或广度优先搜索(BFS)来寻找增广路径。

- 如果找到了增广路径,将路径上的顶点的匹配状态进行交替,即从未匹配转为匹配,从匹配转为未匹配。

这样可以扩展当前的匹配集。

- 如果没有找到增广路径,则转到第二阶段。

3. 第二阶段:为了找到最优匹配,需要修改图中的权重,使得原问题转化为一个完美匹配的问题。

具体步骤如下:
- 从所有未匹配的顶点中找到最小权重的边,并将该权重减去其他边的权重。

- 对于所有已匹配的顶点,将其权重加上其他边的权重。

- 重新回到第一阶段,继续寻找增广路径。

4. 重复执行第一阶段和第二阶段,直到无法找到更多的增广路径。

此时,得到了最优匹配。

匈牙利算法的时间复杂度为O(n^3),其中n是顶点数目。

它在解决二分图最大权匹配问题上表现出色,并被广泛应用于实际问题,如任务分配、资源调度等领域。

gmm算法理解

gmm算法理解

gmm算法理解
GMM算法,即高斯混合模型算法,是一种常用的聚类算法,用于将数据点划分为不同的组或类别。

它的基本思想是使用多个高斯分布来描述数据的统计特性,每个高斯分布代表一个类别。

通过估计每个高斯分布的参数,可以确定数据点属于哪个类别。

在GMM算法中,每个高斯分布由均值向量和协方差矩阵描述。

均值向量表示数据的中心位置,而协方差矩阵表示数据的形状和方向。

算法的目标是找到最优的均值向量和协方差矩阵,以最大化数据的似然性。

为了实现这个目标,GMM算法使用EM算法(期望最大化算法)进行迭代优化。

EM算法包括两个步骤:E步骤和M步骤。

在E步骤中,根据当前的参数估计,计算每个数据点属于每个类别的概率。

然后,在M步骤中,使用这些数据点的概率来更新每个类别的均值向量和协方差矩阵。

通过不断迭代这两个步骤,GMM算法可以逐渐优化参数,直到收敛。

GMM算法的优点是可以处理任意形状的数据分布,并且能够自动确定类别的数量。

它还可以通过调整高斯分布的
数量和参数来控制模型的复杂性。

然而,GMM算法也存在一些缺点,例如对初始参数的敏感性和计算复杂性较高。

在实际应用中,GMM算法常用于图像分割、语音识别、异常检测等领域。

通过合理地选择高斯分布的数量和参数,GMM算法可以有效地对数据进行聚类和分析,提取出有用的信息。

hungarian method

hungarian method

hungarian methodHungarian method是一种经典的解决分配问题的算法。

该算法在二十世纪五六十年代由匈牙利数学家Dénes Kőnig和Jenő Egerváry所发明,用于解决在线性规划中常见的任务分配问题。

这种算法结合了图论和线性规划的技术,是一种非常高效和精准的优化算法。

1. 问题定义在任务分配问题中,我们需要将n项活动分配给n个人,每个人只能完成一项活动。

每项活动有一个与之相关联的成本或权重,我们需要最小化这些权重的总和。

该问题可描述为一个n*n的矩阵,其中每个元素aij代表将任务i分配给人j所需的代价。

2. 算法步骤Hungarian method的实现步骤如下:(1)首先,对原始的代价矩阵进行列减法和行减法,得到一个新的矩阵。

(2)使用最小化(或最大化)算法,将矩阵的元素分组为行和列,并将它们连接起来。

(3)通过在每个组内选择最小的元素并在每个组之间进行替换来得到最优解。

(4)如果问题没有得到解决,则回到步骤1并继续执行算法,直到找到最优解为止。

3. 矩阵的处理在第一步中,我们需要对原始的代价矩阵进行行减法和列减法。

对于每一行和每一列,我们从其中选择一个最小的元素,并将该最小元素从行(或列)的其他元素中减去。

通过这种方式,我们可以得到一个新的矩阵,它的元素最少有一个为0。

该矩阵称为减法矩阵。

4. 匈牙利算法的实现在第二步中,我们使用最小化算法将减法矩阵的元素分组为行和列。

我们将行中的最小元素和列中的最小元素连接起来,并用直线穿过它们。

接下来,我们用相邻线覆盖矩阵的其他元素,直到矩阵的每个元素都被覆盖。

第三步是通过在组内选择最小元素并在组和列之间进行替换来获得最优解的。

如果我们无法替换元素,例如在第二步中,我们没有找到足够的相邻行或列,则需要回到第1步并继续。

5. 求解复杂度的分析Hungarian method是一种精确的分配算法,可以在多项多项任务分配问题上得到最优解。

匈牙利匹配算法的原理

匈牙利匹配算法的原理

匈牙利匹配算法的原理匈牙利匹配算法(也被称为二分图匹配算法或者Kuhn-Munkres算法)是用于解决二分图最大匹配问题的经典算法。

该算法由匈牙利数学家Dénes Kőnig于1931年提出,并由James Munkres在1957年进行改进。

该算法的时间复杂度为O(V^3),其中V是图的顶点数。

匹配问题定义:给定一个二分图G=(X,Y,E),X和Y分别代表两个不相交的顶点集合,E表示连接X和Y的边集合。

图中的匹配是指一个边的集合M,其中任意两条边没有公共的顶点。

匹配的相关概念:1.可增广路径:在一个匹配中找到一条没有被占用的边,通过这条边可以将匹配中的边个数增加一个,即将不在匹配中的边添加进去。

2. 增广路径:一个可增广路径是一个交替序列P=v0e1v1e2v2...ekvk,其中v0属于X且不在匹配中,v1v2...vk属于Y且在匹配中,e1e2...ek在原图中的边。

3.增广轨:一个交替序列形如V0E1V1E2...EkVk,其中V0属于X且不在匹配中,V1V2...Vk属于Y且在匹配中,E1E2...Ek在原图中的边。

增广轨是一条路径的特例,它是一条从X到Y的交替序列。

1.初始时,所有的边都不在匹配中。

2.在X中选择一个点v0,如果v0已经在匹配中,则找到与v0相连的在Y中的顶点v1、如果v1不在匹配中,则(v0,v1)是可增广路径的第一条边。

3. 如果v1在匹配中,则找到与v1相连的在X中的顶点v2,判断v2是否在匹配中。

依此类推,直到找到一个不在匹配中的点vn。

4.此时,如果n是奇数,则(n-1)条边在匹配中,这意味着我们找到了一条增广路径。

如果n是偶数,则(n-1)条边在匹配中,需要进行进一步的处理。

5.如果n是偶数,则将匹配中的边和非匹配中的边进行颠倒,得到一个新的匹配。

6.对于颠倒后的匹配,我们再次从第2步开始,继续寻找增广路径。

7.重复步骤2到步骤6,直到找不到可增广路径为止,此时我们得到了最大匹配。

全网最详细、最深的四类莫队算法讲解

全网最详细、最深的四类莫队算法讲解

• 我们来分析一下时间复杂度
• 这道题代码细节很重要,听懂了并不意味着会写,会写也不意味着能写对
CX数颜色
树上莫队
引入:luogu P4074 [WC2013]狗粮公园
• YQY和KXR建立了一座狗粮公园,公园里不仅有美丽的风景,还有免费狗粮 发放点。 • 狗粮公园结构奇特,由n个免费狗粮发放点构成,可以依次将其编号为1~n。 有n-1条双向道路连接着这些发放点,并且整个公园是联通的。 • YQY发放的狗粮种类丰富 ,总共有m种,依次编号为1~m,每一个狗粮 发放处都只发放某种特定的狗粮,我们用C[i]来表示第i号发放点发放的狗粮。 • 来到公园里游玩的游客都不喜欢走回头路,他们总是从某个特定的发放点出 发前往另一个特定的发放点,并吃路上YQY发的狗粮。
输入格式: 输入文件第一行包含两个正整数N和M。N为袜子的数量,M为PQF所提的询问的数 量。接下来一行包含N个正整数Ci,其中Ci表示第i只袜子的颜色,相同的颜色用相同 的数字表示。再接下来M行,每行两个正整数L,R表示一个询问。 输出格式: 包含M行,对于每个询问在一行中输出分数A/B表示从该询问的区间[L,R]中随机抽出 两只袜子颜色相同的概率。若该概率为0则输出0/1,否则输出的A/B必须为最简分数。 (详见样例) 输入样例: 输出样例: 64 2/5 123332 0/1 26 1/1 13 4/15 35 16
带修莫队
• 把询问和修改分开,修改就是按照读入的顺序记录修改位置,修改前值,修 改后值;询问要记录左右端点,Tim,id(表示在此查询前做过了Tim次修改, 这是第id个查询) • 然后给询问排序(修改千万不能排),然后排序肯定也要改,我们把L所在 块做第一关键字,R所在块做第二关键字,Tim做第三关键字。 • 排完序在解决询问时,比普通莫队多需要一个指针Time,表示已经完成了多 少个修改。然后在普通莫队前面判读是否要时光推移或时光倒流即可

莫队算法的应用

莫队算法的应用

莫队算法的应用
莫队算法是一种离线查询算法,主要应用于解决一类不带修改的区间查询问题。

其基本思想是将询问按照某种顺序排序,然后按照排序后的顺序依次处理询问,从而得到每个询问的答案。

在处理每个询问时,莫队算法利用相邻两个询问之间的信息,通过局部调整的方式,将前一个询问的解答转化为后一个询问的解答,避免了重复计算和全局扫描,从而提高了算法的效率。

莫队算法的应用非常广泛,可以解决很多实际问题。

比如给定一个长度为N的数组,数组中所有元素的大小不超过N,需要回答M个查询,每个查询的形式是L和R,要求计算在范围[L, R]中至少出现3次的数字的个数。

这个问题可以使用莫队算法来解决。

具体来说,我们可以将数组分块,然后按照左端点所在块为第一关键字、右端点为第二关键字对询问进行排序。

然后依次处理排序后的询问,利用相邻两个询问之间的信息,通过增加或删除元素的方式,动态维护当前区间内至少出现3次的数字的个数。

这样就可以在O(N√N)的时间复杂度内解决该问题。

除了上述应用外,莫队算法还可以应用于其他领域,如字符串处理、图论等。

在字符串处理中,可以利用莫队算法解决一些涉及子串的问题,如最长回文子串、最长重复子串等。

在图论中,可以利用莫队算法解决一些涉及图上路径的问题,如路径长度、路径上的最大值等。

需要注意的是,在使用莫队算法时,需要根据具体问题的特点选择合适的排序方式和维护方式,以达到最优的算法效率。

总之,莫队算法是一种非常实用的离线查询算法,可以应用于各种领域解决不同的问题。

掌握莫队算法的基本思想和应用技巧对于提高算法设计和解决问题的能力非常重要。

支持向量机原理(四)SMO算法原理

支持向量机原理(四)SMO算法原理

⽀持向量机原理(四)SMO算法原理 在SVM的前三篇⾥,我们优化的⽬标函数最终都是⼀个关于\alpha向量的函数。

⽽怎么极⼩化这个函数,求出对应的\alpha向量,进⽽求出分离超平⾯我们没有讲。

本篇就对优化这个关于\alpha向量的函数的SMO算法做⼀个总结。

1. 回顾SVM优化⽬标函数 我们⾸先回顾下我们的优化⽬标函数: \underbrace{ min }_{\alpha} \frac{1}{2}\sum\limits_{i=1,j=1}^{m}\alpha_i\alpha_jy_iy_jK(x_i,x_j) - \sum\limits_{i=1}^{m}\alpha_i s.t. \; \sum\limits_{i=1}^{m}\alpha_iy_i = 0 0 \leq \alpha_i \leq C 我们的解要满⾜的KKT条件的对偶互补条件为:\alpha_{i}^{*}(y_i(w^Tx_i + b) - 1 + \xi_i^{*}) = 0 根据这个KKT条件的对偶互补条件,我们有:\alpha_{i}^{*} = 0 \Rightarrow y_i(w^{*} \bullet \phi(x_i) + b) \geq 1 0 <\alpha_{i}^{*} < C \Rightarrow y_i(w^{*} \bullet \phi(x_i) + b) = 1 \alpha_{i}^{*}= C \Rightarrow y_i(w^{*} \bullet \phi(x_i) + b) \leq 1 由于w^{*} = \sum\limits_{j=1}^{m}\alpha_j^{*}y_j\phi(x_j),我们令g(x) = w^{*} \bullet \phi(x) + b=\sum\limits_{j=1}^{m}\alpha_j^{*}y_jK(x, x_j)+ b^{*},则有:\alpha_{i}^{*} = 0 \Rightarrow y_ig(x_i) \geq 1 0 < \alpha_{i}^{*} < C\Rightarrow y_ig(x_i) = 1 \alpha_{i}^{*}= C \Rightarrow y_ig(x_i) \leq 12. SMO算法的基本思想 上⾯这个优化式⼦⽐较复杂,⾥⾯有m个变量组成的向量\alpha需要在⽬标函数极⼩化的时候求出。

(莫队算法)两题莫队算法统计数量的入门题

(莫队算法)两题莫队算法统计数量的入门题

(莫队算法)两题莫队算法统计数量的⼊门题因为这两题差不多,⽽且⽐较简单,就放⼀起,做了这题,这种题⽬就是巨⽔的题了。

随便写都⾏。

Powerful array题意:多次查询数列中从L到R每个数字出现次数的平⽅乘这个数字的和。

代码:1 #include <cstdio>2 #include <cstring>3 #include <iostream>4 #include <cmath>5 #include <map>6 #include <vector>7 #include <algorithm>89using namespace std;1011const int maxn = 200010;12const int bk = 350;13int n, q;14int a[maxn];15struct Query {16int l, r, index;17 };18int cnt[maxn * 5];1920 Query query[maxn];2122bool cmp(Query a, Query b) {23if(a.l / bk == b.l / bk)return a.r < b.r;24else return a.l / bk < b.l / bk;25 }2627long long ans[maxn];28long long res = 0;2930void add(int x) {31 res += x * (2 * cnt[x] + 1);32 cnt[x]++;33 }3435void del(int x) {36 cnt[x]--;37 res -= x * (2 * cnt[x] + 1);38 }3940int main() {41 scanf("%d", &n);42 scanf("%d", &q);43for(int i = 1; i <= n; i++) {44 scanf("%d", &a[i]);45 }46for(int i = 0; i < q; i++) {47 scanf("%d%d", &query[i].l, &query[i].r);48 query[i].index = i;49 }50 sort(query, query + q, cmp);51int left = 1, right = 0;52for(int i = 0; i < q; i++) {53if(right < query[i].r) {54for(int j = right + 1; j <= query[i].r; j++) {55 add(a[j]);56 }57 } else {58for(int j = right; j > query[i].r; j--) {59 del(a[j]);60 }61 }62 right = query[i].r;63if(left < query[i].l) {64for(int j = left; j < query[i].l; j++) {65 del(a[j]);66 }6768 } else {69for(int j = left - 1; j >= query[i].l; j--) {70 add(a[j]);71 }72 }73 left = query[i].l;74 ans[query[i].index] = res;75 }76for(int i = 0; i < q; i++) {77 printf("%lld\n", ans[i]);7879 }8081return0;82 }View CodeSona题意:多次查询数列中L到R买个数字出现次数的⽴⽅和。

区间求和(莫队算法)

区间求和(莫队算法)

区间求和(莫队算法)输⼊描述:第⼀⾏,两个整数n,m第⼆⾏,总共n 个数,代表这个数列接下来m ⾏,每⾏两个整数l,r ,代表⼀个询问输出描述:输出总共m ⾏,对于每个询问,输出这个询问对应的答案⽰例1输⼊2 53 41 103 710 51 3 2456 4 5 6 71 52 53 41 103 7输出7329151467329备注:1≤n,m≤1e51≤ai ≤1e51≤l,r≤n经典莫队算法:维护区间某个数的出现次数但是这个让求的是区间内的ai*num[i]如果区间内有两个5就是加上5*2+5*2不是简单的加a[i]#include<iostream>#include<algorithm>using namespace std;const int maxn=5e5+100;typedef long long ll;int n,m;int a[maxn];ll ans[maxn];int vis[maxn];struct node{int l,r;int id;}t[maxn];int mp[maxn],block,belong[maxn];bool cmp(node x,node y){if (belong[x.l]!=belong[y.l]){return belong[x.l]<belong[y.l];}else {if (belong[x.l]&1){return x.r<y.r;}else{return x.r>y.r;}}}ll res;void remove(int pos){res-=1ll*a[pos]*vis[a[pos]]*vis[a[pos]];//先把之前的权值减去在加上之后的权值 vis[a[pos]]--;res+=1ll*a[pos]*vis[a[pos]]*vis[a[pos]];}void add(int pos){res-=1ll*a[pos]*vis[a[pos]]*vis[a[pos]];vis[a[pos]]++;res+=1ll*a[pos]*vis[a[pos]]*vis[a[pos]];}int main(){scanf("%d%d",&n,&m);block=sqrt(n);for(int i=1;i<=n;i++){scanf("%d",&a[i]);belong[i]=(i-1)/block+1;}//分块处理for(int i=1;i<=m;i++){scanf("%d%d",&t[i].l,&t[i].r);t[i].id=i;}sort(t+1,t+m+1,cmp);int l=1,r=0;int ql,qr;for(int i=1;i<=m;i++){ql=t[i].l,qr=t[i].r;while(l<ql){remove(l++);}while(l>ql){add(--l);}while(r>qr){remove(r--);}while(r<qr){add(++r);}ans[t[i].id]=res;}for(int i=1;i<=m;i++){printf("%lld\n",ans[i]);}}。

AcWing算法进阶课莫队

AcWing算法进阶课莫队

AcWing算法进阶课莫队基础莫队题⽬:HH 有⼀串由各种漂亮的贝壳组成的项链。

HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出⼀段贝壳,思考它们所表达的含义。

HH 不断地收集新的贝壳,因此他的项链变得越来越长。

有⼀天,他突然提出了⼀个问题:某⼀段贝壳中,包含了多少种不同的贝壳?这个问题很难回答,因为项链实在是太长了。

于是,他只好求助睿智的你,来解决这个问题。

输⼊格式第⼀⾏:⼀个整数 NN,表⽰项链的长度。

第⼆⾏:NN 个整数,表⽰依次表⽰项链中贝壳的编号(编号为 00 到 10000001000000 之间的整数)。

第三⾏:⼀个整数 MM,表⽰ HH 询问的个数。

接下来 MM ⾏:每⾏两个整数,LL 和 RR,表⽰询问的区间。

输出格式MM ⾏,每⾏⼀个整数,依次表⽰询问对应的答案。

数据范围1≤N≤500001≤N≤50000,1≤M≤2×1051≤M≤2×105,1≤L≤R≤N1≤L≤R≤N输⼊样例:61 2 3 4 3 531 23 52 6输出样例:224代码:#include <bits/stdc++.h>using namespace std;const int N = 50010, M = 200010, S = 1000010;int n, m, T;int w[N], ans[M];struct Q{int l, r, i, x, y;inline Q() {}inline Q(int l, int r, int i) : l(l), r(r), i(i) {x = l / T, y = r;}inline friend bool operator< (const Q &a, const Q &b){return a.x == b.x ? (a.x & 1) ? a.y < b.y : a.y > b.y : a.x < b.x;}}q[M];int cnt[S];void add(int x, int& res){//第⼀次出现,说明出现了新的贝壳,标记+1if (!cnt[x]) res ++;cnt[x] ++;}void del(int x, int& res){//将当前-1,如果-1为0,则贝壳种类-1cnt[x] --;if (!cnt[x]) res --;}int main(){scanf("%d", &n);for (int i = 1; i <= n; i ++ ) scanf("%d", &w[i]);scanf("%d", &m);T = sqrt((double) n * n / m);for (int i = 0; i < m; i ++ ){int l, r; scanf("%d%d", &l, &r);q[i] = {l, r, i};}sort(q, q + m);// for (int i = 0; i < m; i ++ )// printf("[l = %d, r = %d]\n", q[i].l, q[i].r);for (int k = 0, l = 1, r = 0, res = 0; k < m; k ++ ){while (l < q[k].l) del(w[l ++ ], res);while (l > q[k].l) add(w[-- l ], res);while (r < q[k].r) add(w[++ r ], res);while (r > q[k].r) del(w[r -- ], res);ans[q[k].i] = res;}for (int i = 0; i < m; i ++ ) printf("%d\n", ans[i]);return 0;}待修莫队题⽬:墨墨购买了⼀套 NN ⽀彩⾊画笔(其中有些颜⾊可能相同),摆成⼀排,你需要回答墨墨的提问。

【洛谷日报#183】你以为莫队只能离线?莫队的在线化改造

【洛谷日报#183】你以为莫队只能离线?莫队的在线化改造

【洛谷日报#183】你以为莫队只能离线?莫队的在线化改造写在前面算法来源:朝田诗乃某天在文化课上发呆的时候随意YY的前置知识:莫队(废话)在阅读之前请保证你已熟练掌握以上知识,否则请先移步[洛谷日报第48期]莫队算法初探引言先来看一题可爱的莫队题。

[国家集训队]数颜色 / 维护队列题面:墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。

墨墨会向你发布如下指令:1、 Q L R 代表询问你从第 L 支画笔到第 R 支画笔中一共有几种不同颜色的画笔。

2、 R P Col 把第P支画笔替换为颜色Col。

为了满足墨墨的要求,你知道你需要干什么了吗?本题强制在线本来这是可以用莫队轻松解决的题,可是总有毒瘤出题人把他拿去强制在线。

诗乃很愤怒,于是尝试对莫队算法进行在线化改造。

这辈子都不会写树套树的!一、普通莫队的改造回顾一下莫队算法:我们将所有询问离线排好序,然后每一次从上一个询问区间转移过来。

若我们要使莫队算法在线,“从上一个询问区间转移过来”变得不可行。

我们需要预先处理好某些区间的答案,让这些区间成为莫队中的“上一个区间”,这些区间我们称为特征区间。

特征区间需要满足:1、能用可以接受的时间复杂度全部处理出来2、所有询问能用可以接受的时间复杂度由某个特征区间转移而来。

那么我们考虑选取一些“特征点”,将任意两个特征点之间的区间全部作为特征区间。

假设每隔d步选取一个特征点,那么预处理复杂度为O(n^2/d),每次询问复杂度为O(d)(左端点移动d/2步,右端点移动d/2步),随意证明d=\sqrt{n}为最优。

这里设第i个特征点为s_i特征区间选取完毕后,我们需要保存特征区间的信息。

包括:1.区间答案2.莫队所需要的信息(如区间中每种颜色的出现次数),这往往是几个数组。

对于第2个信息,直接维护显然会爆空间。

由于绝大多数莫队维护的信息具有区间可减的性质(如出现次数),因此我们只需要维护区间[1,s_i]中的信息,读取的时候进行前缀和加减一下即可。

能用莫队做的题

能用莫队做的题

能用莫队做的题
莫队算法是一种常用的优化算法,通常用于求解区间查询问题。

它的优势在于可以将时间复杂度从O(n^2)降低到O(n√n),使得在大规模数据处理中更加高效。

莫队算法的应用非常广泛,涵盖了众多领域。

下面我将介绍几个可以用莫队算法解决的问题。

首先,莫队算法可以用于求解区间众数。

给定一个长度为n的数组,以及q个查询,每个查询给出一个区间[l,r],要求求解该区间中出现次数最多的元素。

使用莫队算法可以在O(n√n)的时间复杂度内解决这个问题。

其次,莫队算法还可以用于求解区间不同元素个数。

给定一个长度为n的数组,以及q个查询,每个查询给出一个区间[l,r],要求求解该区间中不同元素的个数。

莫队算法可以在O(n√n)的时间复杂度内解决这个问题。

此外,莫队算法还可以用于求解区间内的最大和最小值。

给定一个长度为n的数组,以及q个查询,每个查询给出一个区间[l,r],要求求解该区间中的最大值和最小值。

莫队算法可以在O(n√n)的时间复杂度内解决这个问题。

最后,莫队算法还可以用于求解区间中的第k大或第k小元素。

给定一个长度为n的数组,以及q个查询,每个查询给出一个区间[l, r]和一个整数k,要求求解该区间中第k大或第k小的元素。

莫队算法可以在O(n√n)的时间复杂度内解决这个问题。

总结来说,莫队算法是一种高效的算法,在解决区间查询问题方面有着广泛的应用。

它的时间复杂度为O(n√n),能够在大规模数据处理中发挥重要作用。

无论是求解区间众数、区间不同元素个数、区间最大最小值还是求解第k大或第k小元素,莫队算法都能够提供较好的解决方案。

迷宫算法详解

迷宫算法详解

迷宫算法详解
嘿,朋友们!今天咱就来好好唠唠迷宫算法!
你想啊,迷宫就像是一个错综复杂的大谜团,对吧?咱走在迷宫里,不就像一只无头苍蝇到处乱撞嘛(就如同你在一个陌生的城市里找路一样)!而迷宫算法呢,就是帮助我们找到走出这个谜团的路。

比如说深度优先搜索算法。

这就好像你下定决心要一条道走到黑,不撞南墙不回头(就像你非要搞清楚一个谜题,不管多困难都要试下去)!你沿着一个方向一直走,直到走不通了,再退回来换个方向走。

还有广度优先搜索算法呢。

它就像是你小心翼翼地一层一层探索,把每一个可能的方向都先探一探(就如同你在整理房间,先把这个区域的都处理好再去下一个)。

在解决迷宫问题的时候,我们得灵活运用这些算法呀。

要是只用一种方法,那多死板呀!比如说有些迷宫特别复杂,就得用广度优先搜索来慢慢地、稳稳地探索。

不然你一头扎进去,说不定就在里面打转出不来喽(那不就像在大雾天开车,没有个好的指引可不行)!
总之呢,迷宫算法真的超级有趣又超级实用!大家一定要好好去研究研究哦!相信你们会发现其中的奇妙之处的!。

树上莫队例题

树上莫队例题

树上莫队例题树上莫队(Tree Mo's Algorithm)是莫队算法(Mo's Algorithm)的一种扩展,用于在树上进行区间查询。

莫队算法是一种处理静态区间查询的算法,通过离线处理所有查询,可以在较短的时间内回答每个查询。

树上莫队算法则在树上的节点上执行莫队算法。

以下是一个树上莫队算法的例题,该例题通常涉及树上的路径查询。

在这个例子中,我们考虑一个树,每个节点都有一个权值,然后会有一系列的查询,每个查询包含一个节点和一个整数k,要求找到以给定节点为根的子树中权值小于等于k 的节点数量。

问题描述:给定一棵树,每个节点有一个权值。

接下来有Q 个查询,每个查询包含两个整数u 和k。

对于每个查询,找到以节点u 为根的子树中权值小于等于k 的节点数量。

输入:第一行包含两个整数N 和Q,分别表示树的节点数量和查询数量。

第二行包含N 个整数,表示每个节点的权值。

接下来N-1 行,每行包含两个整数u 和v,表示树上存在一条边连接节点u 和节点v。

接下来Q 行,每行包含两个整数u 和k,表示一个查询。

输出:对于每个查询,输出一个整数,表示以节点u 为根的子树中权值小于等于k 的节点数量。

样例输入:6 31 2 3 4 5 61 21 32 42 53 61 32 54 10样例输出:343在这个例子中,树的结构如下:1/ \2 3/| \4 5 6对于第一个查询(1, 3),以节点1 为根的子树中,权值小于等于 3 的节点有1、2、3,所以输出为3。

对于第二个查询(2, 5),以节点2 为根的子树中,权值小于等于5 的节点有2、4、5,所以输出为4。

对于第三个查询(4, 10),以节点4 为根的子树中,权值小于等于10 的节点有4,所以输出为1。

最大熵和积算法

最大熵和积算法

最大熵和积算法
最大熵和积算法(Maximum Entropy and Minimum Divergence Algorithm,MEMD)是一种用于解决数据分类问题的机器学习算法。

它基于最大熵原理和最小散度原理,能够在保证分类结果准确性的前提下,最大限度地保持模型的简洁性。

最大熵原理是指在已知一些约束条件的情况下,选择概率分布最均匀的模型作为
最优模型。

最小散度原理是指在已知两个概率分布的情况下,选择最小散度的模
型作为最优模型。

MEMD算法将这两个原理结合起来,通过学习约束条件下的最大熵模型,然后使
用最小散度原理进行模型简化,从而得到一个简洁、准确的分类模型。

具体来说,MEMD算法首先使用最大熵模型进行分类,然后通过最小化KL散度来优化分类结果,使得分类结果更加准确。

最后,算法会对模型进行正则化,以保
证模型的简洁性。

MEMD算法具有较好的分类效果和泛化能力,适用于文本分类、情感分析、图像
分类等应用场景。

序列最小最优化算法smo算法-bitjoy

序列最小最优化算法smo算法-bitjoy

序列最小最优化算法(SMO 算法)SMO 算法是要解如下凸二次规划的对偶问题:min a 12∑∑αi αj N j=1N i=1y i y j K(x i ,x j )−∑αi N i=1 (1) s.t. ∑αi y i =0N i=1 (2) 0 ≤ αi ≤C, i =1,2,…,N (3) 在这个问题中,变量是拉格朗日乘子,一个变量αi 对应于一个样本点(x i ,y i );变量的总数等于训练样本容量N 。

SMO 算法是一种启发式算法,其基本思路是:如果所有变量的解都满足此最优化问题的KKT 条件(Karush-Kuhn-Tucker conditions ),那么这个最优化问题的解就得到了。

因为KKT 条件是该最优化问题的充分必要条件。

否则,选择两个变量,固定其他变量,针对这两个变量构建一个二次规划问题。

这个二次规划问题关于这两个变量的解应该更接近原始二次规划问题的解,因为这会使得原始二次规划问题的目标函数值变得更小。

重要的是,这时子问题可以通过解析方法求解,这样就可以大大提高整个算法的计算速度。

子问题有两个变量,一个是违反KKT 条件最严重的那一个,另一个由约束条件自动确定。

如此,SMO 算法将原问题不断分解为子问题并对子问题求解,进而达到求解原问题的目的。

注意,子问题的两个变量中只有一个是自由变量,假设α1 ,α2 为两个变量,α3 ,α4,…,αN 固定,那么由等式约束(2)可知α1+α2= −y 1∑αi y i N i=3如果α2 确定,那么α1 也随之确定,所以子问题中同时更新两个变量。

整个SMO 算法包括两个部分:求解两个变量二次规划的解析方法;选择变量的启发式方法。

1. 两个变量二次规划的求解方法不失一般性,假设选择的两个变量是α1 ,α2 ,其他变量αi (i=3,4,…,N )是固定的,于是SMO 的最优化问题(1)~(3)的子问题可以写成:min α1,α2 W (α1,α2)=12K 11α12+12K 22α22+y 1y 2K 12α1α2 −(α1+α2)+y 1α1∑y i αi K i1+y 2α2∑y i αi K i2N i=3N i=3 (4) s.t. α1y 1+α2y 2=−∑y i αi =N i=3ζ (5)0 ≤ αi ≤C, i =1,2 (6) 其中,K ij =K(x i ,x j ),i ,j = 1,2,…,N ,ζ是常数,目标函数式(4)中省略了不含α1 ,α2 的常数项。

C-COT数据结构与算法(2020)

C-COT数据结构与算法(2020)

C-COT数据结构与算法(2020)树上莫队算法江湖传闻,莫队算法能够解决一切区间查询问题。

这样说来,莫队算法也能够解决一切树上路径查询问题,将树上操作转化为DFS序列上的区间操作即可。

当然考虑到,树上路径在DFS序列中的性质,还要会求LCALCA。

考虑上图中的树,其DFS序为其任意点对aa、bb之间的路径,具有如下性质,令lcalca为aa、bb的最近公共祖先:若lcalca是aa、bb之一,则aa、bb之间的InIn时刻的区间或者OutOut时刻区间就是其路径。

例如AKAK之间的路径就对应区间ABEEFKABEEFK,或者KFBCGGHHIICAKFBCGGHHIICA。

若lcalca另有其人,则aa、bb之间的路径为In[a]In[a]、Out[b]Out[b]之间的区间或者In[b]In[b]、Out[a]Out[a]之间的区间。

另外,还需额外加上lcalca考虑EKEK路径,对应为EFKEFK 再加上BB。

考虑EHEH之间的路径,对应为EFKKFBCGGHEFKKFBCGGH 再加上AA。

这样就能将路径查询转化为对应的区间查询。

另外需要注意到,在DFS序上应用莫队算法移动指针时,如果是欲添加的节点在当前区间内已经有一个了,这实际上应该是一个删除操作;如果欲删除的节点在当前区间内已经有两个了,这实际上应该是一个添加操作。

SPOJ COT2(编号为10707)要求查询路径之间不同权值的个数,是一个典型的树上莫队题目。

首先求出DFS序,然后弄个数据结构和Tarjan算法把所有询问的LCALCA求出,再根据LCALCA的结果将原始询问转化为区间问题,最后使用莫队算法。

#include cstdio#include vector#include algorithmusing namespace std;int const SIZE = 40100;int const BLOCK_SIZE = 300;--利用hash记录LCAstruct Hash{typedef struct __t{int a;int b;__t(int aa=0,int bb=0):a(aa),b(bb){}} key_t;typedef int value_t;enum{MOD=0x1FFFFF};key_t keys[MOD+1];value_t values[MOD+1];int head[MOD+1];int next[MOD+1];int toUsed;Hash():toUsed(0){fill(head,head+MOD+1,-1);}void clear(){fill(head,head+toUsed,-1);toUsed=0;}int getKey(key_t constkey)const{int ret = 17;ret = ret * 37 + key.a;ret = ret * 37 + key.b;return ret;void insert(key_t constkey,value_t constvalue){int k = getKey(key) MOD;keys[toUsed] = key;values[toUsed] = value;next[toUsed] = head[k];head[k] = toUsed++;value_t find(key_t constkey)const{int k = getKey(key) MOD;for(int i=head[k];i!=-1;i=next[i]){if ( keys[i].a == key.a keys[i].b == key.b ) return values[i];return 0;void disp(FILE*fp)const{for(int i=1;itoUsed;++i){fprintf(fp,"(%d %d): %d",keys[i].a,keys[i].b,values[i]);struct edge_t{int next;}Edge[SIZE1];int ECnt = 1;int Vertex[SIZE] = {0};inline void mkEdge(int a,int b){Edge[ECnt].to = b;Edge[ECnt].next = Vertex[a];Vertex[a] = ECnt++;Edge[ECnt].to = a;Edge[ECnt].next = Vertex[b];Vertex[b] = ECnt++;--生成DFS序int InIdx[SIZE],OutIdx[SIZE];int NewIdx[SIZE1];int NCnt = 1;void dfs(int node,int parent){NewIdx[NCnt] = node;InIdx[node] = NCnt++;for(int next=Vertex[node];next;next=Edge[next].next){ int to = Edge[next].to;if ( to != parent ) dfs(to,node);NewIdx[NCnt] = node;OutIdx[node] = NCnt++;--Tarjan算法中用到的并查集int Father[SIZE];int find(int x){return x==Father[x]?x:Father[x]=find(Father[x]);} bool Flag[SIZE] = {false};vectorvectorint Questions(SIZE,vectorint());--Tarjan算法一次性求出所有的LCAvoid Tarjan(int u,int parent){Father[u] = u;Flag[u] = true;for(int next=Vertex[u];next;next=Edge[next].next){int to = Edge[next].to;if ( to == parent ) continue;Tarjan(to,u);Father[to] = u;vectorintvec=Questions[u];for(vectorint::iteratorit=vec.begin();it!=vec.end();++it){int v = *it;if ( Flag[v] ){int r = find(v);Lca.insert(Hash::key_t(u,v),r);Lca.insert(Hash::key_t(v,u),r);struct _t{bool operator (_t constlhs,_t constrhs){int ln = lhs.s - BLOCK_SIZE;int rn = rhs.s - BLOCK_SIZE;return ln rn || ( ln == rn lhs.e rhs.e );int A[SIZE];_t B[100000];--将原树上的路径问题转化为DFS序中的区间问题inline void mkQuestion(int a,int b,int idx){int lca = Lca.find(Hash::key_t(a,b));if ( lca == a || lca == b ){int t = lca == a ? b : a;B[idx].s = OutIdx[t];B[idx].e = OutIdx[lca];B[idx].lca = 0;B[idx].lca = lca;if ( OutIdx[a] InIdx[b] ) B[idx].s = OutIdx[a], B[idx].e = InIdx[b];else B[idx].s = OutIdx[b], B[idx].e = InIdx[a];int MoAns;int Ans[100000],Cnt[SIZE];inline void insert(int n){if ( 1 == ++Cnt[n] ) ++MoAns;inline void remove(int n){if ( 0 == --Cnt[n] ) --MoAns;void MoOp(int idx){int k = NewIdx[idx];if ( Flag[k] ) remove(A[k]);else insert(A[k]);Flag[k] ^= 1;void Mo(){sort(B,B+M);fill(Flag,Flag+N+1,false);int curLeft = 1;int curRight = 0;MoAns = 0;for(int i=0;iM;++i){while( curRight B[i].e ) MoOp(++curRight); while( curLeft B[i].s ) MoOp(--curLeft); while( curRight B[i].e ) MoOp(curRight--); while( curLeft B[i].s ) MoOp(curLeft++); if ( B[i].lca ){ Ans[B[i].idx] = MoAns + ( 0 == Cnt[A[B[i].lca]] ? 1 : 0 );Ans[B[i].idx] = MoAns;void init(int n){ECnt = NCnt = 1;fill(Vertex,Vertex+n+1,0);fill(Flag,Flag+n+1,false);int getUnsigned(){char ch = getchar();while( ch '9' || ch '0' ) ch = getchar();int ret = 0;do ret = ret * 10 + (int)(ch-'0');while( '0' = (ch=getchar()) ch = '9' );return ret;int W[SIZE];bool read(){if ( EOF == scanf("%d",N) ) return false;M = getUnsigned();init(N);--权值输入并离散化for(int i=1;i=N;++i) W[i] = A[i] = getUnsigned();sort(W+1,W+N+1);int* pn = unique(W+1,W+N+1);for(int i=1;i=N;++i) A[i] = lower_bound(W+1,pn,A[i]) - W; for(int i=1;iN;++i){a = getUnsigned();b = getUnsigned();mkEdge(a,b);dfs(1,0);for(int i=0;iM;++i){B[i].s = getUnsigned();B[i].e = getUnsigned();B[i].idx = i;Questions[B[i].s].push_back(B[i].e);Questions[B[i].e].push_back(B[i].s);Tarjan(1,0);for(int i=0;iM;++i) mkQuestion(B[i].s,B[i].e,i);return true;int main(){--freopen("1.txt","r",stdin);while ( read() ){for(int i=0;iM;++i)printf("%d",Ans[i]);return 0;SUM(decode(TO_CHAR(a.telfeedate,c)较高层捕获对象类别的语义概念,而较低层编码更多的具有区性的特征,来捕获类别内的变形。

莫耶夫公式(一)

莫耶夫公式(一)

莫耶夫公式(一)莫耶夫公式什么是莫耶夫公式?莫耶夫公式(Meyer formula)是一种应用于计算机科学领域的公式,通常用于解决数学问题中的递归关系。

它由著名的计算机科学家莫耶夫提出,被广泛应用于动态规划和分治算法中。

莫耶夫公式的形式莫耶夫公式可以表示为以下形式:T(n) = a * T(n/b) + f(n)其中: - T(n)是问题规模为n时的时间复杂度 - a是将问题分解为更小子问题时的子问题个数 - n/b是每个子问题的规模 - f(n)是除去问题划分和子问题解决外,剩余操作所需的时间复杂度莫耶夫公式的应用动态规划在动态规划中,莫耶夫公式可以帮助我们分析问题的时间复杂度。

举个例子,假设我们要计算一个斐波那契数列的第n项,可以使用以下递归函数:def fibonacci(n):if n <= 1:return nelse:return fibonacci(n-1) + fibonacci(n-2)根据莫耶夫公式,我们可以将该递归函数的时间复杂度表示为:T(n) = T(n-1) + T(n-2) + O(1)其中,T(n-1)和T(n-2)是递归调用的时间复杂度,O(1)是剩余操作的时间复杂度。

通过莫耶夫公式,我们可以得知斐波那契数列的计算时间复杂度约为O(2^n)。

分治算法莫耶夫公式也被广泛应用于分治算法的时间复杂度分析。

以快速排序算法为例,它可以使用以下递归函数进行实现:def quick_sort(arr):if len(arr) <= 1:return arrpivot = arr[len(arr) // 2]left = [x for x in arr if x < pivot]middle = [x for x in arr if x == pivot]right = [x for x in arr if x > pivot]return quick_sort(left) + middle + quick_sort(right)根据莫耶夫公式,我们可以将快速排序算法的时间复杂度表示为:T(n) = 2 * T(n/2) + O(n)其中,T(n/2)是递归调用的时间复杂度,O(n)是剩余操作的时间复杂度。

分治 —— 莫队算法

分治 —— 莫队算法

【概述】
莫队算法(mo's algorithm)是用来解决离线区间不修改询问问题,可以将复杂度优化到 O(n^1.5),除去普通的莫队算法外,还有带修改的莫队、树上莫队等等。

莫队常用于维护区间答案,比如:对于一个长度为 n 的序列,给出 m 次询问,每次询问区间 [l,r] 内有多少个不同的颜色,其中 n,m<=100000.
对于一个序列,当知道 [L,R] 的信息时,可在 O(1) 的时间复杂度内求出 [L-1,R]、[L,R-1]、[L+1,R]、[L,R+1] 的两个询问之间的状态跳转。

信息,其思想基础是两个询问之间的状态跳转
其本质是利用分治的思想,分块排序优化暴力搜索,减少搜索区间之间的覆盖长度,从而优化时间复杂度
【算法】
普通莫队:点击这里
带修莫队:点击这里
【例题】
Fast Queries(LightOJ-1188)(普通莫队模版题):点击这里
Little Elephant and Array(CF-220B)(普通莫队+卡常数):点击这里
Powerful array(CF-86D)(普通莫队+卡常数):点击这里
Sona(NBUT-1457)(普通莫队+离散化):点击这里
小Z的袜子(BZOJ-2038)(普通莫队+公式推导):点击这里
XOR and Favorite Number(CF-617E)(普通莫队+异或前缀和):点击这里
数颜色(洛谷-P1903)(带修莫队):点击这里
Machine Learning(CF-940F)(带修莫队+离散化):点击这里
Game(HDU-6610)(异或性质+带修莫队):点击这里。

相关主题
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

莫队算法详解本文翻译自MO’s Algorithm (Query square root decomposition),作者anudeep2011,发表日期为2014-12-28。

由于最近碰到一些莫队算法的题目,找到的相关中文资料都比较简略,而这篇英语文章则讲解的比较详细,故翻译成中文与大家分享。

由于本人水平有限,错误在所难免,请谅解。

下面是译文。

我又发现了一个有用,有趣但网上资源非常少的话题。

在写作之前,我做了一个小调查,令我惊讶的是,几乎所有的印度程序员都不知道该算法。

学习这个很重要,事实上所有的codeforces 红名程序员都使用这个算法,比如在div 1 C 题和D 题中。

在一年半以前没有这方面的题目,但从那时起这类题目的数量就爆发了!我们可以期待这在未来的比赛中会有更多的这类题目。

莫队算法详解问题描述复杂度的简单的解法一个解决上述问题的算法及其正确性对上述算法的复杂性证明 - 上述算法的适用范围习题和示例代码问题描述给定一个大小为N 的数组,数组中所有元素的大小<=N 。

你需要回答M 个查询。

每个查询的形式是L ,R 。

你需要回答在范围[ L ,R ]中至少重复3次的数字的个数。

例如:数组为{ 1,2,3,1,1,2,1,2,3,1 }(索引从0开始)查询:L = 0,R = 4。

答案= 1。

在范围[L ,R]中的值 = { 1,2,3,1,1 },只有1是至少重复3次的。

查询:L = 1, R = 8。

答案= 2。

在范围[L ,R]中的值 = { 2,3,1,1,2,1,2,3 }, 1重复3遍并且2重复3次。

至少重复3次的元素数目=答案= 2。

复杂度的简单的解法对于每一个查询,从L 至R 循环,统计元素出现频率,报告答案。

考虑M = N 的情况,以下程序在最O ()N 2O (∗N )N −−√O ()N 22坏的情况运行在for each query:answer = 0count[] = 0for i in {l..r}:count[array [i]]++if count[array [i]] == 3:answer++对上述算法稍作修改。

它仍然运行在add (position):count[array [position]]++if count[array [position]] == 3:answer++remove (position):count[array [position]]--if count[array [position]] == 2:answer--currentL = 0currentR = 0answer = 0count[] = 0for each query:// currentL 应当到 L, currentR 应当到 Rwhile currentL < L:remove (currentL)currentL++while currentL > L:add (currentL)currentL--while currentR < R:add (currentR)currentR++while currentR > R:remove (currentR)currentR--output answer最初我们总是从L 至R 循环,但现在我们从上一次查询的位置调整到当前的查询的位置。

如果上一次的查询是L = 3,R = 10,则我们在查询结束时有currentL=3、currentR=10。

如果下一个查询是L = 5,R = 7,则我们将currentL 移动到5,currentR 移动到7。

add 函数 意味着我们添加该位置的元素到当前集合内,并且更新相应的回答。

O ()n 2O ()n 2remove 函数 意味着我们从当前集合内移除该位置的元素,并且更新相应的回答。

一个解决上述问题的算法及其正确性莫队算法仅仅调整我们处理查询的顺序。

我们得到了M 个查询,我们将把查询以一个特定的顺序进行重新排序,然后处理它们。

显然,这是一个离线算法。

每个查询都有L 和R ,我们称呼其为“起点”和“终点”。

让我们将给定的输入数组分为块。

每一块的大小为 。

每个“起点”落入其中的一块。

每个“终点”也落入其中的一块。

如果某查询的“起点”落在第p 块中,则该查询属于第p 块。

该算法将处理第1块中的查询,然后处理第2块中的查询,等等,最后直到第块。

我们已经有一个顺序、查询按照所在的块升序排列。

可以有很多的查询属于同一块。

从现在开始,我会忽略(其它,译者注,所有括号内斜体同)所有的块,只关注我们如何询问和回答第1块。

我们将对所有块做同样的事。

(第1块中的)所有查询的“起点”属于第1块,但“终点”可以在包括第1块在内的任何块中。

现在让我们按照R 值升序的顺序重新排列这些查询。

我们也在所有的块中做这个操作。

(指每个块块内按R 升序排列。

)最终的排序是怎样的?所有的询问首先按照所在块的编号升序排列(所在块的编号是指询问的“起点”属于的块)。

如果编号相同,则按R 值升序排列。

例如考虑如下的询问,假设我们会有3个大小为3的块(0-2,3-5,6-8):{0, 3} {1, 7} {2, 8} {7, 8} {4, 8} {4, 4} {1, 2}让我们先根据所在块的编号重新排列它们{0, 3} {1, 7} {2, 8} {1, 2} (|){4, 8} {4, 4}(|) {7, 8}现在我们按照R 的值重新排列{1, 2} {0, 3} {1, 7} {2, 8}(|) {4, 4} {4, 8}(|) {7, 8}现在我们使用与上一节所述相同的代码来解决这个问题。

上述算法是正确,因为我们没有做任何改变,只是重新排列了查询的顺序。

对上述算法的复杂性证明 - 我们完成了莫队算法,它只是一个重新排序。

可怕的是它的运行时分析。

原来,如果我们按照我上面指定的顺序,我们所写的的代码运行在时间复杂度上。

可怕,这是正确的,仅仅是重新排序查询使我们把复杂度从降低到,而且也没有任何进一步的代码上的修改。

好哇!我们将以的复杂度AC 。

看看我们上面的代码,所有查询的复杂性是由 4个while 循环决定的。

前2个while 循环可以表述为“左指针(currentL)的移动总量”,后2个 while 循环可以表述为“右指针(currentR)的移动总量”。

这两者的和将是总复杂性。

N −−√N /=N −−√N −−√N −−√O (∗N )N −−√O ()N 2O (×N )N −−√O ()N 2O (×N )N −−√O (×N )N −−√最重要的。

让我们先谈论右指针。

对于每个块,查询是递增的顺序排序,所以右指针(currentR )按照递增的顺序移动。

在下一个块的开始时,指针可能在extreme end (最右端?) ,将移动到下一个块中的最小的R 处。

这意味着对于一个给定的块,右指针移动的量是。

我们有块,所以总共是。

太好了!让我们看看左指针怎样移动。

对于每个块,所有查询的左指针落在同一个块中,当我们从一个查询移动到另个一查询左指针会移动,但由于前一个L 与当前的L 在同一块中,此移动是(块大小)的。

在每一块中左指针的移动总量是,Q 是落在那个块的查询的数量。

对于所有的块,总的复杂度为。

就是这样,总复杂度为上述算法的适用范围如前所述,该算法是离线的,这意味着当我们被强制按照特定的顺序查询时,我们不能再使用它。

这也意味着当有更新操作时我们不能用这个算法。

不仅如此,一个重要的可能的局限性:我们应该能够编写add 和remove 函数。

会有很多的情况下,add 是平凡的 (指复杂度?),但remove 不是。

这样的一个例子就是我们想要求区间内最大值。

当我们添加的元素,我们可以跟踪最大值。

但当我们删除元素则不是平凡的。

不管怎样,在这种情况下,我们可以使用一个集合来添加元素,删除元素和报告 最小值(作者想说最大值?)。

在这种情况下,添加和删除操作都是(导致了的算法)。

在许多情况下,我们可以使用此算法。

在一些情况下,我们也可以使用其它的数据结构,如线段树,但对于一些问题使用莫队算法的是必须的。

让我们在下一节中讨论几个问题。

习题和示例代码DQUERY – SPOJ :区间内不同元素的数量=出现次数>=1的元素个数,所以跟以上讨论的问题是一样的。

点击此处查看示例代码注意:该代码提交会超时,加上更快的输入输出(传说中的输入输出挂?) 就能AC 。

为了使代码整洁,去掉了快的输入输出。

(评论中说将remove 和add 声明为inline 内联函数就可以AC 。

)Powerful array – CF Div1 D : 这道题是必须用莫队算法的例子。

我找不到任何其它解法。

CF Div1 D 意味着这是一道难题。

看看用了莫队算法就多简单了。

你只需要修改上述代码中的add(), remove() 函数。

GERALD07 – CodechefGERALD3 – CodechefTree and Queries – CF Div1 DPowerful Array – CF Div1 DJeff and Removing Periods – CF Div1 DO (N )O ()N −−√O (N ∗)N −−√O ()N −−√O (Q ∗)N −−√O (M ∗)N −−√O ((N +M )∗)=O (N ∗)N −−√N −−√O (1)O (logN )O (N ∗∗logN )N −−√Sherlock and Inversions – Codechef (省略结束语)。

相关文档
最新文档