这题正解不是莫队,但是确实看起来比较像莫队,所以就当练手。
这题卡常卡的厉害,cout都会tle。
莫队一般都是求区间的结果,这个恰好相反,取非区间的结果。
先全处理出来一共有多少,把中间的减掉,如果中间把某个值的元素全部占有,结果就减一。
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<queue>
#include<map>
#include<vector>
#include<iomanip>
#include<algorithm>
#include<string>
#include<cmath>
#include<cstdio>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
const ll mod = 1e9 + 7;
const double eps = 1e-5;
const double PI = acos(-1);
void acc_ios()
{
ios::sync_with_stdio(false);
cin.tie(0);
}
struct node
{
int l, r, id, pos;
};
node qu[maxn];
int vis[maxn], res[maxn], a[maxn], ans;
bool cmp(node a, node b)//可以优化200ms左右的排序方法,还挺关键的
{
if(a.pos == b.pos)
{
if(a.pos % 2)
return a.r < b.r;
else
return a.r > b.r;
}
else
return a.l < b.l;
}
void add(int x)
{
vis[a[x]]--;
//cout<<"a"<<a[x]<<endl;
if(vis[a[x]] == 0) ans--;
}
void del(int x)
{
vis[a[x]]++;
// cout<<"d"<<a[x]<<endl;
if(vis[a[x]] == 1)
ans++;
}
int main()
{
//acc_ios();
int n, m;
while(scanf("%d%d", &n, &m) != EOF)
{
ans = 0;
memset(vis, 0, sizeof(vis));
vis[0] = 1000;
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
vis[a[i]]++;
if(vis[a[i]] == 1)
ans++;
}
int x = sqrt(n);
for(int i = 0; i < m; i++)
{
scanf("%d%d", &qu[i].l, &qu[i].r);
qu[i].l++, qu[i].r--;
qu[i].id = i;
qu[i].pos = qu[i].l / x;
}
//cout<<ans<<endl;
int l = 1, r = 0;
sort(qu, qu + m, cmp);
for(int i = 0; i < m; i++)
{
int L = qu[i].l, R = qu[i].r;
//cout<<L<<" "<<R<<endl;
while(l < L) del(l++);
while(l > L) add(--l);
while(r < R) add(++r);
while(r > R) del(r--);
res[qu[i].id] = ans;
}
for(int i = 0; i < m; i++)
printf("%d\n", res[i]);
}
return 0;
}