首页 > 其他分享 >莫队

莫队

时间:2024-05-21 15:42:20浏览次数:22  
标签:rt node return int -- lt 莫队

膜拜“莫涛”巨佬

思路

如果说给你一个数组,有 \(q\) 组询问,询问一个区间的区间和,那么有最原始的做法。维护一个左端点和一个右端点,每次一位一位移动断点,那么时间复杂度是 \(n \times q\),那么如果我们将查询存起来,按一种我们想要的顺序去做呢?我们就可以排序,排序规则就是:

B = sqrt(n);
bool cmp(node _x, node _y) {
  if (_x.l / B != _y.l / B) {
    return _x.l / B < _y.l / B;
  }
  return _x.r < _y.r;
}

具体来说就是先将左端点分成一个一个的块,右端点则按从小到大排序即可。

时间复杂度

左端点在一个块内做多移动 \(n\) 次(|1,3,5,4,2|数字表示顺序),那么有 \(\sqrt{n}\) 的块,那就最多移动 \(n\times\sqrt{n}\)次
右端点也是一样
那么时间复杂度就是 \(O(2\timesn\times\sqrt{n})\)
code:

#include <bits/stdc++.h>

using namespace std;

#define int long long

const int N = 2e5 + 5, B = 455;

struct node {
	int l, r, id;
}a[N];

int n, q, x[N], ans[N];

bool cmp(node _x, node _y) {
	if (_x.l / B != _y.l / B) {
		return _x.l / B < _y.l / B;
	}
	return _x.r < _y.r;
}

signed main() {
	cin >> n >> q;
	for (int i = 1; i <= n; i++) {
		cin >> x[i];
	}
	for (int i = 1; i <= q; i++) {
		cin >> a[i].l >> a[i].r;
		a[i].id = i; 
	}
	sort(a + 1, a + q + 1, cmp);
	for (int i = 1, lt = 1, rt = 1, tmp = x[1]; i <= q; i++) {
		while (lt < a[i].l) {				
			tmp -= x[lt];		
		  lt++;
		}
		while (rt < a[i].r) {				  
			rt++;		
		  tmp += x[rt];		
		}
		while (lt > a[i].l) {			
		  lt--;
			tmp += x[lt];
		}
		while (rt > a[i].r) {
			tmp -= x[rt];
			rt--;
		}
		ans[a[i].id] = tmp;
	}
	for (int i = 1; i <= q; i++) {
		cout << ans[i] << "\n";
	}
	return 0;
} 

优势

如:做算区间内有多少种颜色时极其方便

#include <bits/stdc++.h>

using namespace std;

const int N = 2e5 + 5, B = 455;

struct node {
	int l, r, id;
}a[N];

int n, q, x[N], ans[N], cnt = 0, mp[N + 5];

vector<int> v;

bool cmp(node _x, node _y) {
	if (_x.l / B != _y.l / B) {
		return _x.l / B < _y.l / B;
	}
	return _x.r < _y.r;
}

void check(int u, int op) {
	if (op == 1) {
		if (!mp[u]) {
			cnt++;
		}
		mp[u]++;
	}
	else {
		mp[u]--;
		if (!mp[u]) {
			cnt--;
		}
	}
}

int main() {
	cin >> n >> q;
	for (int i = 1; i <= n; i++) {
		cin >> x[i];
		v.push_back(x[i]); 
	}
	sort(v.begin(), v.end());
	for (int i = 1; i <= n; i++) {
		x[i] = lower_bound(v.begin(), v.end(), x[i]) - v.begin(); 
	}
	for (int i = 1; i <= q; i++) {
		cin >> a[i].l >> a[i].r;
		a[i].id = i; 
	}
	sort(a + 1, a + q + 1, cmp);
	for (int i = 1, lt = 1, rt = 0; i <= q; i++) {
		while (lt < a[i].l) {				
			check(x[lt], -1);	
		  lt++;
		}
		while (rt < a[i].r) {				  
			rt++;	
			check(x[rt], 1);		
		}
		while (lt > a[i].l) {			
		  lt--;
			check(x[lt], 1);
		}
		while (rt > a[i].r) {
			check(x[rt], -1);
			rt--;
		}
		ans[a[i].id] = cnt;
	}
	for (int i = 1; i <= q; i++) {
		cout << ans[i] << "\n";
	}
	return 0;
} 

标签:rt,node,return,int,--,lt,莫队
From: https://www.cnblogs.com/libohan/p/18204185

相关文章

  • 莫队(板子)
    莫队参考博客玄学暴力区间操作算法PPT解释的很清楚啦~,导致我没什么可写的\(qwq\)把所有询问离线下来后排序(左端点按块,右端点升序),然后从一个小区间通过左右端点的移动扩大区间,更新答案。复杂度主要在区间扩展,也就是左右指针的移动,对于莫队所有的优化几乎都是调整分块或排......
  • 莫队算法(基础莫队)小结(也做markdown测试)
    莫队基础莫队本质是通过排序优化了普通尺取法的时间复杂度。考虑如果某一列询问的右端点是递增的,那么我们更新答案的时候,右指针只会从左往右移动,那么i指针的移动次数是$O(n)$的。当然,我们不可能让左右端点都单调来做到总体$O(n)$。考虑对左端点进行分块。莫队排序:左端点按......
  • CF940F.Machine Learning-带修莫队、Mex
    给一个序列\(a\),两个操作:1、给\(l,r\),设\(a_l,\dots,a_r\)这些数集中每个数\(v\)的出现次数是\(c_v\),要求\(\mathrm{mex}(c_i)\).2、单点修改\(1\leqn,q\leq10^5\),时限4s这种一眼看过去很难维护的信息,一般就先找找性质。首先注意到关键性质:要求的是出现次数......
  • 莫队小计
    莫队考虑一个经典的问题。对一个数列进行\(m\)次区间求和。暴力需要\(O(nm)\),但是莫队可以优化到\(O(n\sqrtm)\)。思想具有启发式思维。假如我们知道\([l,r]\)的和为\(k\)。在此基础上\([l-1,r],[l,r+1]\)都可以很快得到。莫队是对上一个问题解决这个问题。要给对问题......
  • 回滚莫队
    简介:远看是莫队(\(r\)),近看是暴力(\(l\),以及左右端点在同一块)。还记得普通莫队里面怎么说的吗?注意两个操作有时候会西掉一个,有时候还要在数据结构上操作,但这不在这篇文章的范围内。所以,这篇文章就会讲述如何应对“两个操作西掉一个”的情况。删除西掉了(更加常见)和正常莫队的排......
  • 正常莫队
    简介:原汁原味。区间不同数字数量\(N\le10^5,Q\le10^5,A_i\le10^9\)。我们当然可以暴力,时间复杂度\(O(QN)\)。Improvment1我们离散化,然后区间\([l,r]\)可以快速扩展到\([l-1,r],[l+1,r],[l,r-1],[l,r+1]\)。维护扩展中新来的信息。具体怎么从某......
  • 莫队-目录
    这个算法有多个变体。如果你只需要某些变体,点开这些变体的页面即可。这个算法有多个变体。如果你只需要某些变体,点开这些变体的页面即可。这个算法有多个变体。如果你只需要某些变体,点开这些变体的页面即可。普通莫队......
  • 分块莫队——维护队列
    题目描述样例输入2312Q12R12Q12样例输出21题目分析首先它是一个离线莫队(在线超时QAQ)离线首先存下它所有的询问和修改,分别存,询问要存下是第几次,以便后续输出,还要存下时间是第几个命令,比较询问和修改的时间,相应的变换颜色,最后整体输出#include<bits/stdc++.h>......
  • P4168 [Violet] 蒲公英 (莫队的强制在线)
    前言当个乐子看就行所用时间不如分块正解快虽然在线莫队实质也是分块[Violet]蒲公英题目背景亲爱的哥哥:你在那个城市里面过得好吗?我在家里面最近很开心呢。昨天晚上奶奶给我讲了那个叫「绝望」的大坏蛋的故事的说!它把人们的房子和田地搞坏,还有好多小朋友也被它杀掉了。我......
  • [BZOJ4358]permu树上莫队
    先放代码晚上补(争取)#include<bits/stdc++.h>#definefo(x,y,z)for(int(x)=(y);(x)<=(z);(x)++)#definefu(x,y,z)for(int(x)=(y);(x)>=(z);(x)--)typedeflonglongll;usingnamespacestd;inlineintqr(){ charch=getchar();intx=0,f=1; for(;ch<&......