关于莫队的常数问题
  • 板块学术版
  • 楼主Sata_moto
  • 当前回复29
  • 已保存回复29
  • 发布时间2021/9/25 14:07
  • 上次更新2023/11/4 05:42:18
查看原帖
关于莫队的常数问题
118274
Sata_moto楼主2021/9/25 14:07

刚刚用 P1972 [SDOI2009]HH的项链 练了一下莫队模板(虽然现在莫队卡不大过去了),发现操作区间端点左右移动时,以下两种写法的常数差别很大,希望有大佬能说明以下原因。

//这是复杂度优秀的一种

while(l > Q[k].l) ans += (cnt[d[--l]]++ == 0 ? 1 : 0);

//这种就要几乎慢上一倍

while(l > Q[k].l) if(cnt[d[--l]]++ == 0) ans++;

完整代码如下

//faster
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>

using namespace std;
inline int read();

const int N = 1e6 + 10;

int n, m, l, r, d[N], cnt[N], Ans[N], ans, siz;

struct node
{
	int l, r, b, id;
	bool operator < (const node & other ) const
	{
		return b ^ other.b ? l < other.l : ((b & 1) ? r<other.r : r>other.r);
	}
} Q[N];

signed main()
{
	n = read();
	for(register int k = 1; k <= n; k++)
		d[k] = read();
	m = read(), siz = n / sqrt(m * 2 / 3);
	for(register int k = 1; k <= m; Q[k].id = k, k++)
		Q[k].l = read(), Q[k].r = read(), Q[k].b = Q[k].l / siz;
	sort(&Q[1], &Q[m + 1]);

	for(register int k = Q[1].l; k <= Q[1].r; k++)
		if(cnt[d[k]]++ == 0) ans++;
	l = Q[1].l, r = Q[1].r;
	for(register int k = 1; k <= m; k++)
	{

// 问题就出现在这一段上
		while(l > Q[k].l) ans += (cnt[d[--l]]++ == 0 ? 1 : 0);
		while(r < Q[k].r) ans += (cnt[d[++r]]++ == 0 ? 1 : 0);
		while(l < Q[k].l) ans -= (--cnt[d[l++]] == 0 ? 1 : 0);
		while(r > Q[k].r) ans -= (--cnt[d[r--]] == 0 ? 1 : 0);
//-------------------------------------------------
		Ans[Q[k].id] = ans;
	}

	for(register int k = 1; k <= m; k++)
		printf("%d\n", Ans[k]);

	return 0;
}

inline char new_getchar()
{
	static char sz[2048];
	static int size = 0, wz = 0;

	if(size == wz)
	{
		wz = 0;
		size = fread(sz, 1, 2048, stdin);

		if(wz != size)
			return sz[wz++];
		else
			return EOF;
	}
	else
		return sz[wz++];
}

inline int read()
{
	int neg = 1, x = 0, ch = '~';

	while(!(ch >= '0' && ch <= '9')) neg = (ch == '-') ? -1 : 1, ch = getchar();
	while(ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) , x += ch - '0', ch = getchar();

	return x * neg;
}

//slower
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>

using namespace std;
inline int read();

const int N = 1e6 + 10;

int n, m, l, r, d[N], cnt[N], Ans[N], ans, siz;

struct node
{
	int l, r, b, id;
	bool operator < (const node & other ) const
	{
		return b ^ other.b ? l < other.l : ((b & 1) ? r<other.r : r>other.r);
	}
} Q[N];

signed main()
{
	n = read();
	for(register int k = 1; k <= n; k++)
		d[k] = read();
	m = read(), siz = n / sqrt(m * 2 / 3);
	for(register int k = 1; k <= m; Q[k].id = k, k++)
		Q[k].l = read(), Q[k].r = read(), Q[k].b = Q[k].l / siz;
	sort(&Q[1], &Q[m + 1]);

	for(register int k = Q[1].l; k <= Q[1].r; k++)
		if(cnt[d[k]]++ == 0) ans++;
	l = Q[1].l, r = Q[1].r;
	for(register int k = 1; k <= m; k++)
	{

// 问题就出现在这一段上
		while(l > Q[k].l) if(cnt[d[--l]]++ == 0) ans++;
		while(r < Q[k].r) if(cnt[d[++r]]++ == 0) ans++;
		while(l < Q[k].l) if(--cnt[d[l++]] == 0) ans--;
		while(r > Q[k].r) if(--cnt[d[r--]] == 0) ans--;
//-------------------------------------------------
		Ans[Q[k].id] = ans;
	}

	for(register int k = 1; k <= m; k++)
		printf("%d\n", Ans[k]);

	return 0;
}

inline char new_getchar()
{
	static char sz[2048];
	static int size = 0, wz = 0;

	if(size == wz)
	{
		wz = 0;
		size = fread(sz, 1, 2048, stdin);

		if(wz != size)
			return sz[wz++];
		else
			return EOF;
	}
	else
		return sz[wz++];
}

inline int read()
{
	int neg = 1, x = 0, ch = '~';

	while(!(ch >= '0' && ch <= '9')) neg = (ch == '-') ? -1 : 1, ch = getchar();
	while(ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) , x += ch - '0', ch = getchar();

	return x * neg;
}
2021/9/25 14:07
加载中...