莫队算法是一种区间查询算法,它将查询的区间以左端为准分成了sqrt(n)份,然后每份中的区间以右端排序,之后维持一个查询的队列[l,r],记录答案。
注意:一定要先处理r2和r再处理l2和l!(不知道贡献了多少wa...)
例题:
hdoj :
http://acm.hdu.edu.cn/showproblem.php?pid=3874
题目大意:
n次询问,每次询问计算区间中不重复数字的代数和。
AC代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int M = 1000100;
const int S = 200020;
int necklace[M], hashtable[M];
long long ans[S];
int n;
struct Query
{
int l, r, dx;
bool operator < (const Query &i) const
{
int l1 = l/sqrt(n);//将区间分成sqrt(n)份,并以右端排序
int l2 = i.l/sqrt(n);
if(l1 == l2)
return r < i.r;
return l1 < l2;
}
}query[S];
main()
{
int T;
scanf("%d", &T);
while(T--)
{
memset(hashtable, 0, sizeof(hashtable));
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &necklace[i]);
int q;
scanf("%d", &q);
for(int i = 0; i < q; i++)
{
scanf("%d %d", &query[i].l, &query[i].r);
query[i].dx = i;
}
sort(query, query + q);
long long sum = 0;
int l, r, l2 = 0, r2 = 0;
for(int i = 0; i < q; i++)
{
l = query[i].l, r = query[i].r;
if(r2 < r)//对可能出现的四种情况进行处理 一定要先右后左!!
for(int j = r2 + 1; j <= r; j++)
{
if(hashtable[necklace[j]] == 0)
{
sum += necklace[j];
hashtable[necklace[j]]++;
}
else
hashtable[necklace[j]]++;
}
if(r2 > r)
for(int j = r2; j > r; j--)
{
if(hashtable[necklace[j]] == 1)
{
sum -= necklace[j];
hashtable[necklace[j]]--;
}
else if(hashtable[necklace[j]] > 1)
hashtable[necklace[j]]--;
}
if(l2 < l)
for(int j = l2; j < l; j++)
{
if(hashtable[necklace[j]] == 1)
{
sum -= necklace[j];
hashtable[necklace[j]]--;
}
else if(hashtable[necklace[j]] > 1)
hashtable[necklace[j]]--;
}
if(l2 > l)
for(int j = l2 - 1; j >= l; j--)
{
if(hashtable[necklace[j]] == 0)
{
sum += necklace[j];
hashtable[necklace[j]]++;
}
else
hashtable[necklace[j]]++;
}
l2 = l, r2 = r;
ans[query[i].dx] = sum;
}
for(int i = 0; i < q; i++)
printf("%I64d\n", ans[i]);
}
}