莫队算法使用分块的思想,可以解决一类离线区间询问问题。 对于序列上的区间询问问题,如果从 [l,r] 的答案能够 O(1) 扩展到
[l−1,r],[l+1,r],[l,r+1],[l,r−1] 的答案,那么可以在 O(n√n) 的复杂度内求出所有询问的答案。
将整个区间分为√n个块,然后进行排序。L需要在对应的块中,而在上面的前提下R要递增。
P1972 [SDOI2009]HH的项链
这是一道可以用莫队写的题,最后两个点需要你吸一口氧气才能过`#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e6+4;
struct query {
int l, r,num;
}p[maxn];
int sum[maxn] ={0} , belong[maxn];
int cmp(query a, query b) {
return (belong[a.l] ^ belong[b.l]) ? belong[a.l] < belong[b.l] : ((belong[a.l] & 1) ? a.r < b.r : a.r > b.r);
}
int a[maxn],ans[maxn];
int main()
{
int n, m ;
scanf("%d",&n);
int size = sqrt(n);
int bnum = ceil((double)n/size);
for(int i=1;i<=bnum;i++)
for(int j =(i-1) * size + 1 ;j <= i * size ;j++)
belong[j] = i;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&p[i].l,&p[i].r);
p[i].num = i ;
}
sort(p+1,p+m+1,cmp);
int l = 1,r =0 ,now =0;
for(int i=1;i<=m;i++)
{
int ql = p[i].l, qr = p[i].r;
while(l<ql) now -= !--sum[a[l++]];
while(l>ql) now += !sum[a[--l]]++;
while(r<qr) now += !sum[a[++r]]++;
while(r>qr) now -= !--sum[a[r--]];
ans[p[i].num] = now;
}
for(int i=1;i<=m;i++)
{
printf("%d\n",ans[i] );
}
}`
杭电多校第三场Game
题意就是一个数组两种操作,交换两个相邻点(修改一个异或前缀和)询问子区间的种相同元素的个数。明显是一个单点修改的待、带修改的莫队,就是再普通的莫队上再加上一维时间(所以又有人叫三维莫队),想学出门右转洛谷日报或者百度。
代码如下
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5 + 10;
const int M = 1e5 + 10;
const int K = (1 << 21) + 5;
int a[N],b[N]={0},p[N];
ll ans[N],cnt[K],sum=0;
int block;
struct node {int st,ed,t,id;}q[M];
bool operator < (node a, node b) {
if (a.st / block != b.st / block) return a.st < b.st;
if (a.ed / block != b.ed / block) return a.ed < b.ed;
return a.t < b.t;
}
void add(int pos){sum+=cnt[b[pos]]++;}
void sub(int pos){sum-=--cnt[b[pos]];}
void upd(int i,int t)
{
if(q[i].st <= p[t] && p[t]<= q[i].ed)sub(p[t]);
b[p[t]]^=a[p[t]];
swap(a[p[t]],a[p[t]+1]);
b[p[t]]^=a[p[t]];
if(q[i].st <=p[t]&&p[t]<=q[i].ed)add(p[t]);
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
memset(cnt,0,sizeof cnt);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
b[i] = b[i-1]^a[i];
}
int qcnt=0,kcnt=0,op,l,r,pla;
for(int i=1;i<=m;i++)
{
scanf("%d",&op);
if(op==1)
{
scanf("%d%d",&l,&r);
q[++qcnt] = node{l-1,r,kcnt,qcnt};
}
else {
scanf("%d",&pla);
p[++kcnt] = pla;
}
}
block = max(10, (int)pow(n, 2. / 3));
sort(q+1,q+1+qcnt);
sum = 0;
int st=0,ed = -1,t= 0 ;
for(int i=1;i<=qcnt;i++)
{
while(st<q[i].st)sub(st++);
while(st>q[i].st)add(--st);
while(ed<q[i].ed)add(++ed);
while(ed>q[i].ed)sub(ed--);
while(t<q[i].t) upd(i,++t);
while(t>q[i].t) upd(i,t--);
ans[q[i].id] = 1ll*(ed-st) * (ed-st+1)/2 - sum;
}
for(int i=1;i<=qcnt;i++)
printf("%lld\n",ans[i]);
}
return 0;
}