莫队算法其实就是暴力分块,举个形象的例子,如果你要在大海里找一个东西,你是会一会儿在南半球找,然后一会儿又到北半球找呢,还是先在南半球找完了,再在北半球找。(这里假设物体是不动的)很明显是先在北半球找后再在南半球找或者相反。莫队就是这样的原理,主要是减少了转换区域时的损耗。
对于询问
1.先以起点排序,放在各个桶内,桶是sqrt(n)那么大的,然后每个桶内以终点排序。
然后查询的时候是每个桶从小到大,你会发现起点是在桶里乱动的(这就好比你在南半球乱找)消耗是sqrt(n)的,桶只有sqrt(n)那么大。
2.然后发现终点是渐渐增大的(终点最多移动n次嘛)这就相当于你从南半球渐渐的往北半球找。这里是o(n)的
3.然后可能还换桶,这里的复杂度还是sqrt(n)的
所以对于每次询问复杂度是sqrt(n)的。当然如果配合上树状数组什么的复杂度就要乘一个log了比如这道题。
对于此题主要是要注意ins的作用还有就是给每个询问一个id因为排序后再输出的话已经不是原来的顺序了。
这题可能还能用可持久化做吧,速度大概能达到200000ms左右吧如果姿势不对的话,姿势对的话估计就是10000ms左右
还有如果你有什么东西掉海里了,那是不用找的。。。。。。。。。。。。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<math.h>
using namespace std;
struct query
{
int l, r,a,b,num;
};
query q[1000021];
int sum1[100020], sum2[100020], n, belong[100020],m,a[100020],isin[100020];
int ans1[1000021], ans2[1000021];
bool com(query a, query b)
{
if (belong[a.l] == belong[b.l])return a.r < b.r;
return belong[a.l] < belong[b.l];
}
void add1(int pos,int kind)
{
while (pos <= n)
{
sum1[pos]+=kind; pos += pos&(-pos);
}
}
void add2(int pos,int kind)
{
while (pos <= n)
{
sum2[pos]+=kind; pos += pos&(-pos);
}
}
int fsum(int l)
{
int ans = 0;
while (l)
{
ans += sum1[l]; l -= l&(-l);
}
return ans;
}
int ssum(int l)
{
int ans = 0;
while (l)
{
ans += sum2[l]; l -= l&(-l);
}
return ans;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <=n; i++)
scanf("%d", &a[i]);
int len = sqrt((double)n) + 1;
for (int i = 1; i <= n; i++)belong[i] = i%len == 0 ? (i / len) : (i / len + 1);
for (int i = 0; i < m; i++)
scanf("%d%d%d%d", &q[i].l, &q[i].r, &q[i].a, &q[i].b), q[i].num = i;
sort(q, q + m, com);
int l = 1; int r = 0;
for (int i = 0; i < m; i++)
{
while (l < q[i].l)
{
add1(a[l], -1);
isin[a[l]]--;
if (!isin[a[l]])add2(a[l], -1);
l++;
}
while (l > q[i].l)
{
l--;
add1(a[l], 1);
if (!isin[a[l]]) add2(a[l], 1);
isin[a[l]]++;
}
while (r < q[i].r)
{
r++;
add1(a[r], 1);
if (!isin[a[r]]) add2(a[r], 1);
isin[a[r]]++;
}
while (r > q[i].r)
{
add1(a[r], -1);
isin[a[r]]--;
if(!isin[a[r]])add2(a[r], -1);
r--;
}
ans1[q[i].num] = fsum(q[i].b)-fsum(q[i].a-1);
ans2[q[i].num]= ssum(q[i].b) - ssum(q[i].a - 1);
}
for (int i = 0; i < m; i++)
printf("%d %d\n", ans1[i], ans2[i]);
return 0;
}