首页 > 其他分享 >莫队

莫队

时间:2022-10-24 21:35:01浏览次数:58  
标签:cnt int res ++ include 莫队 id

P1494 [国家集训队] 小 Z 的袜子

莫队模板

点击查看代码

#include <math.h>
#include <stdio.h>
#include <string.h>
#include <algorithm>
const int N = 50005;
typedef long long LL;
int n, m, len, w[N], cnt[N]; // cnt维护出现个数
struct Query { int id, l, r; } queries[N];
LL ans1[N], ans2[N];
int get(int x) { return (x - 1) / len + 1; }
void upd(int x, LL &res, int dif) { // res为每个数出现次数平方和
	res -= (LL)cnt[x] * cnt[x], cnt[x] += dif, res += (LL)cnt[x] * cnt[x];
}
int main() {
	scanf("%d%d", &n, &m), len = sqrt(n);
	for(int i = 1; i <= n; i ++) scanf("%d", w + i);
	for(int i = 0; i < m; i ++) scanf("%d%d", &queries[i].l, &queries[i].r), queries[i].id = i;
	std::sort(queries, queries + m, [&](const Query &x, const Query &y) {
		if(get(x.l) != get(y.l)) return get(x.l) < get(y.l);
		return x.r < y.r;
	});
	LL res = 0, d;
	for(int k = 0, i = 0, j = 1; k < m; k ++) {
		auto [id, l, r] = queries[k];
		if(l == r) {
			ans2[id] = 1;
			continue;
		}
		while(i < r) upd(w[++ i], res, 1);
		while(i > r) upd(w[i --], res, -1);
		while(j < l) upd(w[j ++], res, -1);
		while(j > l) upd(w[-- j], res, 1);
		ans1[id] = res - (r - l + 1);
		ans2[id] = (r - l + 1LL) * (r - l);
		d = std::__gcd(ans1[id], ans2[id]);
		ans1[id] /= d, ans2[id] /= d;
	}
	for(int i = 0; i < m; i ++) printf("%lld/%lld\n", ans1[i], ans2[i]);
	return 0;
}

P1972 [SDOI2009] HH的项链

莫队模板

点击查看代码

#include <math.h>
#include <stdio.h>
#include <string.h>
#include <algorithm>

const int N = 1e6 + 5;

int n, m, len, a[N], ans[N];
struct Query { int id, l, r; } querys[N];
int cnt[N];

int get_id(int x) { return (x - 1) / len + 1; }

void add(int x, int &res) {
	if(!cnt[x]) res ++;
	cnt[x] ++;
}
void del(int x, int &res) {
	cnt[x] --;
	if(!cnt[x]) res --;
}

int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; i ++) scanf("%d", a + i);
	scanf("%d", &m);
	len = sqrt(n);
	for(int i = 0; i < m; i ++)
		scanf("%d%d", &querys[i].l, &querys[i].r), querys[i].id = i;
	std::sort(querys, querys + m, [&](const Query &x, const Query &y) {
		if(get_id(x.l) != get_id(y.l)) return get_id(x.l) < get_id(y.l); // 先按块排序,在按右端点排序
		return x.r < y.r; // 有时需要用 get_id是否为奇数来判断用 x.r<y.r还是x.r>y.r
	});
	for(int k = 0, i = 0, j = 1, res = 0; k < m; k ++) {
		auto [id, l, r] = querys[k];
		while(i < r) add(a[++ i], res);
		while(i > r) del(a[i --], res);
		while(j < l) del(a[j ++], res);
		while(j > l) add(a[-- j], res);
		ans[id] = res;
	}
	for(int i = 0; i < m; i ++) printf("%d\n", ans[i]);
	return 0;
}

P1903 [国家集训队] 数颜色 / 维护队列

带修莫队 (l,r,t) 询问:排序方法:l编号,r编号,t 每次移动指针l,r,t, 移动t时分是否在块内的,若在块内
复杂度: a为块长 l: O(am+a*(n/a))=O(am+n) r: O(am+nn/a) t: O(nnt/aa)
a>=sqrt(n) 于是 r:O(am) 最终: a=三次根号(nt) 复杂度=三次根号(nnnnt)

点击查看代码

#include <math.h>
#include <stdio.h>
#include <string.h>
#include <algorithm>
const int N = 133340, M = 1000005;
int n, m, len, mq, mm;
int w[N], cnt[M], ans[N];
struct Query { int id, l, r, t; } queries[N];
struct Modify { int pos, val; } modifies[N];
int get_id(int x) { return (x - 1) / len + 1; }
void add(int x, int &res) {
	if(!cnt[x]) res ++;
	cnt[x] ++;
}
void del(int x, int &res) {
	cnt[x] --;
	if(!cnt[x]) res --;
}
int main() {
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i ++) scanf("%d", w + i);
	for(int i = 0, a, b; i < m; i ++) {
		static char op[2];
		scanf("%s%d%d", op, &a, &b);
		if(*op == 'Q') mq ++, queries[mq] = {mq, a, b, mm};
		else mm ++, modifies[mm] = {a, b};
	}
	len = cbrt((double)n * std::max(1, mm)) + 1;
	std::sort(queries + 1, queries + mq + 1, [&](const Query&x, const Query&y) {
		int xl = get_id(x.l), xr = get_id(x.r), yl = get_id(y.l), yr = get_id(y.r);
		if(xl != yl) return xl < yl;
		if(xr != yr) return xr < yr;
		return x.t < y.t;
	});
	for(int i = 0, j = 1, t = 0, k = 1, res = 0; k <= mq; k ++) {
		auto [id, l, r, tm] = queries[k];
		while(i < r) add(w[++ i], res);
		while(i > r) del(w[i --], res);
		while(j < l) del(w[j ++], res);
		while(j > l) add(w[-- j], res);
		while(t < tm) {
			t ++;
			if(modifies[t].pos >= j && modifies[t].pos <= i) // 在区间[j,i]内
				del(w[modifies[t].pos], res), add(modifies[t].val, res);
			std::swap(w[modifies[t].pos], modifies[t].val);
		}
		while(t > tm) {
			if(modifies[t].pos >= j && modifies[t].pos <= i) // 在区间[j,i]内
				del(w[modifies[t].pos], res), add(modifies[t].val, res);
			std::swap(w[modifies[t].pos], modifies[t].val);
			t --;
		}
		ans[id] = res;
	}
	for(int i = 1; i <= mq; i ++) printf("%d\n", ans[i]);
	return 0;
}

历史研究

历史研究 回滚莫队
维护最大值(或任意不好删除的东西):
右端点在这个块: 暴力
右端点在块外: 下一个块的开头: 只有+ 在这个块内部的: 暴力

点击查看代码

#include <math.h>
#include <stdio.h>
#include <string.h>
#include <algorithm>
const int N = 100005;
typedef long long LL;
int n, m, len;
int w[N], cnt[N];
struct Query { int id, l, r; } queries[N];
int num[N], tot;
LL ans[N];
int get_id(int x) { return (x - 1) / len + 1; }
void add(int x, LL &res) {
	cnt[x] ++;
	res = std::max(res, cnt[x] * LL(num[x]));
}
int main() {
	scanf("%d%d", &n, &m), len = sqrt(n);
	for(int i = 1; i <= n; i ++) scanf("%d", w + i), num[++ tot] = w[i];
	std::sort(num + 1, num + tot + 1), tot = std::unique(num + 1, num + tot + 1) - num - 1;
	for(int i = 1; i <= n; i ++) w[i] = std::lower_bound(num + 1, num + tot + 1, w[i]) - num;
	for(int i = 0; i < m; i ++) scanf("%d%d", &queries[i].l, &queries[i].r), queries[i].id = i;
	std::sort(queries, queries + m, [&](const Query &x, const Query &y) {
		if(get_id(x.l) != get_id(y.l)) return get_id(x.l) < get_id(y.l);
		return x.r < y.r;
	});
	for(int x = 0; x < m; ) { // x表示询问的下标 每次枚举一个块
		int y = x;
		while(y < m && get_id(queries[y].l) == get_id(queries[x].l)) y ++;
		int R = get_id(queries[x].l) * len - 1; // 这个块的右端点
		while(x < y && queries[x].r <= R) { // 被这个块包含的区间: 暴力求
			LL res = 0;
			auto [id, l, r] = queries[x];
			for(int k = l; k <= r; k ++) add(w[k], res);
			ans[id] = res;
			for(int k = l; k <= r; k ++) cnt[w[k]] --; // 清空
			x ++;
		}
		LL res = 0;
		int i = R, j = R + 1;
		while(x < y) {
			auto [id, l, r] = queries[x];
			while(i < r) add(w[++ i], res);
			LL res2 = res; // 备份
			while(j > l) add(w[-- j], res); // 加入块内的
			ans[id] = res;
			while(j <= R) cnt[w[j ++]] --; // 清空
			res = res2;
			x ++;
		}
		memset(cnt, 0, sizeof(cnt)); // 清空
	}
	for(int i = 0; i < m; i ++) printf("%lld\n", ans[i]);
	return 0;
}

P2709 小B的询问

点击查看代码
// 莫队模板
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <algorithm>
const int N = 50005;
typedef long long LL;
int n, m, len, w[N], cnt[N]; // cnt维护出现个数
struct Query { int id, l, r; } queries[N];
LL ans1[N], ans2[N];
int get(int x) { return (x - 1) / len + 1; }
void upd(int x, LL &res, int dif) { // res为每个数出现次数平方和
	res -= (LL)cnt[x] * cnt[x], cnt[x] += dif, res += (LL)cnt[x] * cnt[x];
}
int main() {
	scanf("%d%d", &n, &m), len = sqrt(n);
	for(int i = 1; i <= n; i ++) scanf("%d", w + i);
	for(int i = 0; i < m; i ++) scanf("%d%d", &queries[i].l, &queries[i].r), queries[i].id = i;
	std::sort(queries, queries + m, [&](const Query &x, const Query &y) {
		if(get(x.l) != get(y.l)) return get(x.l) < get(y.l);
		return x.r < y.r;
	});
	LL res = 0, d;
	for(int k = 0, i = 0, j = 1; k < m; k ++) {
		auto [id, l, r] = queries[k];
		if(l == r) {
			ans2[id] = 1;
			continue;
		}
		while(i < r) upd(w[++ i], res, 1);
		while(i > r) upd(w[i --], res, -1);
		while(j < l) upd(w[j ++], res, -1);
		while(j > l) upd(w[-- j], res, 1);
		ans1[id] = res - (r - l + 1);
		ans2[id] = (r - l + 1LL) * (r - l);
		d = std::__gcd(ans1[id], ans2[id]);
		ans1[id] /= d, ans2[id] /= d;
	}
	for(int i = 0; i < m; i ++) printf("%lld/%lld\n", ans1[i], ans2[i]);
	return 0;
}

标签:cnt,int,res,++,include,莫队,id
From: https://www.cnblogs.com/azzc/p/16823059.html

相关文章

  • BZOJ 4810([Ynoi2017]由乃的玉米田-莫队)
    Description由乃在自己的农田边散步,她突然发现田里的一排玉米非常的不美。这排玉米一共有N株,它们的高度参差不齐。由乃认为玉米田不美,所以她决定出个数据结构题这个题是这......
  • 树上莫队 学习笔记
    树上莫队本质上是把树上的结点转化为区间信息,从而使用莫队求解。但是不能直接使用树链剖分的\(\text{dfs}\)序,因为树上任意一条路径所对应的区间不是连续的。此处需要用......
  • 莫队
    排序模板:boolcmp(queryx,queryy){if(id[x.l]==id[y.l]){if(id[x.l]&1==1)returnx.r<y.r;elsereturnx.r>y.r; }elsereturnid......
  • 【SA+莫队】P2336 [SCOI2012]喵星球上的点名
    [SCOI2012]喵星球上的点名题目描述a180285幸运地被选做了地球到喵星球的留学生。他发现喵星人在上课前的点名现象非常有趣。假设课堂上有\(n\)个喵星人,每个喵星人的......
  • 莫队 学习笔记
    基本莫队询问离线,按块排序,\(\sqrtn\)分块,两个指针来回扫。总时间复杂度为\(\Theta(n\sqrtn)\)。带修莫队考虑增加一维时间戳(当前修改次数)。在原有基础上,若左右端......
  • 莫队
    用途问题存在可从区间\(l,r\)\(O(1)\)转移到\(l+1,r\)\(or\)\(l-1,r\)\(or\)\(l,r+1\)\(or\)\(l,r-1\)的时候就可以使用莫队。实现两个指针记录\(l,r\),......
  • 莫队
    一.莫队(静态莫队)我们以LuoguP3901数列找不同为例讲一下静态莫队这道题是个绿题,因为数据比较弱,但真是一道良心的莫队练手题莫队是由前国家队队长莫涛发明的莫队算法......
  • 【luogu P5906】【模板】回滚莫队&不删除莫队
    【模板】回滚莫队&不删除莫队题目链接:luoguP5906题目大意给你一个序列,多次询问每次问一个区间,求里面相同的数的最远间隔距离。思路考虑莫队,发现加入一个点好处理,但是......
  • 2021杭电多校1 J (普通莫队 树状数组)
    题意:给出1e5个二维平面上的坐标点0<=(x,y)<=1e5,1e5个询问,每次问x0,y0到x1,y1的矩阵中有多少y值不同的坐标点。思路:操作只有询问,不强制在线,数据范围1e5,就差把莫......
  • 普通莫队解决区间众数的个数
    SP32900KDOMINO-K-dominantarrayP1997faebdc的烦恼P3709大爷的字符串题被摩尔投票法洗脑半天,发现好像可以直接拿莫队写啊喂!针对原数据离散化,后开一个计数器和一......