学习资料
板子化代码参考
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
", 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
",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
", ans[i]);
return 0;
}