普通莫队学习

学习资料

ouuan's blog


板子化代码参考


int B=n/sqrt(m);//n是序列长度, m是询问数
struct qs{
	//“询问”的结构体
	int id,l,r;//id表示询问编号, l、r分别表示询问区间的左右端点
	bool operator<(const qs& b) const{
		return l/B==b.l/B ? r<b.r : l<b.l;
	}
}q[maxn];
int l=1,r=0;//初始区件
// ------------------------------
void add(int x) {
	//balabala
}
void del(int x) {
	//balabala
}
void mov(int i) {
	//询问区间的转移
	while(l<q[i].l) del(a[l++]);
	while(l>q[i].l) add(a[--l]);
	while(r<q[i].r) add(a[++r]);
	while(r>q[i].r) del(a[r--]);
}

// + + +
// in the main function
// - - -
	sort(q,q+m);
	for(int i=0;i<m;++i) {
		mov(i);//注意初始区间是 [1,0]
		/*
			记录答案
			ans[q[i].id] = balabala
		*/
	}
	for(int i=0;i<m;++i) printf("%d\n", ans[i]);

普通莫队题目浅解

小Z的袜子

询问区间改变的时候,可以 \(O(1)\) 改变答案, 不带修, 可离线, 可用普通莫队。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 51005;

int n,m,col[maxn];
int B;
struct qs{
	int id,l,r;
	bool operator<(const qs& b) const {
		return l/B==b.l/B ? r<b.r : l<b.l;
	}
} q[maxn];

int l=1,r=0;
int fz,fm;
int len,cnt[maxn];
void add(int x) {
	fz+=cnt[x];
	++cnt[x];
	fm+=len;
	++len;
}
void del(int x) {
	--cnt[x];
	fz-=cnt[x];
	--len;
	fm-=len;
}
void mov(int i) {
	while(l<q[i].l) del(col[l++]);
	while(l>q[i].l) add(col[--l]);
	while(r<q[i].r) add(col[++r]);
	while(r>q[i].r) del(col[r--]);
}

int ans[maxn][2];
int gcd(int a,int b) {
	return (!b) ? a : gcd(b,a%b);
}

int main()
{
	scanf("%d%d",&n,&m);
	B = n/sqrt(m);
	for(int i=1;i<=n;++i) scanf("%d",&col[i]);
	for(int i=0;i<m;++i) {
		scanf("%d%d",&q[i].l,&q[i].r);
		q[i].id=i;
	}
	sort(q,q+m);
	for(int i=0;i<m;++i) {
		mov(i);
		if(q[i].l==q[i].r) {
			ans[q[i].id][0]=0;
			ans[q[i].id][1]=1;
			continue;
		}
		int g=gcd(fz,fm);
		ans[q[i].id][0]=fz/g;
		ans[q[i].id][1]=fm/g;
	}
	for(int i=0;i<m;++i) printf("%d/%d\n",ans[i][0],ans[i][1]);
	return 0;
}

小B的询问

询问可离线且不带修
设数 \(k\) 在区间 \([L,R]\) 中出现了 \(cnt_k\) 次,对答案的贡献即为 \((cnt_k)^2\) 每当 \(cnt_k\)\(1\) 时, 贡献变为 \((cnt_k+1)^2 = (cnt_k)^2 + 2*cnt_k + 1\), 即答案增加 \(2*cnt_k + 1\)\(cnt_k\) 减一的情况类似。
区间发生 \(1\) 单位变动答案可 \(O(1)\) 转换
可以使用普通莫队求解。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 51005;
int n,m,k,a[maxn];

int B;
struct qs{
	int id,l,r;
	bool operator<(const qs& b) const{
		return l/B==b.l/B ? r<b.r : l<b.l;
	}
}q[maxn];
int ans[maxn];

int l=1,r=0,cnt[maxn],sum;
void add(int x) {
	sum+=(2*cnt[x]+1);
	++cnt[x];
}
void del(int x) {
	--cnt[x];
	sum-=(2*cnt[x]+1);
}
void mov(int i) {
	while(l<q[i].l) del(a[l++]);
	while(l>q[i].l) add(a[--l]);
	while(r<q[i].r) add(a[++r]);
	while(r>q[i].r) del(a[r--]);
}

int main()
{
	scanf("%d%d%d",&n,&m,&k), B=n/sqrt(m);
	for(int i=1;i<=n;++i) scanf("%d",&a[i]);
	for(int i=0;i<m;++i) scanf("%d%d",&q[i].l,&q[i].r), q[i].id=i;
	sort(q,q+m);
	for(int i=0;i<m;++i) {
		mov(i);
		ans[q[i].id] = sum;
	}
	for(int i=0;i<m;++i) printf("%d\n", ans[i]);
	return 0;
}
posted @ 2020-05-30 17:00  xwmwr  阅读(184)  评论(0编辑  收藏  举报