【SPOJ3267】D-query-莫队算法

来源:互联网 发布:建筑工程招投标软件 编辑:程序博客网 时间:2024/06/05 20:30

测试地址:D-query

题目大意:有N个数,Q个询问,每次询问某个区间[L,R]内有多少不同的数。

做法:这题我用主席树做过,题解请看这里。

而这道题用莫队算法也能做,思考信息的转移:存储一个数组f表示每个数出现的次数,那么每次转移要么插入一个数,要么删除一个数,这样我们判断就很容易:当插入一个数时,如果原来这个数没有出现,那么答案+1;当删除一个数时,如果这个数原来就只剩一个了,那么答案-1。然后直接套莫队算法离线处理询问即可。

想法:这道题目用主席树写的话思想比较复杂(当然也有可能是更简单的方法我没想到),而用莫队算法就可以很优美的解决,所以说莫队算法对于大多数离线区间询问问题还是有很大的作用的。

以下是本人代码:

#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <algorithm>#include <cmath>using namespace std;int n,m,a[30010],f[1000010]={0};struct query{  int l,r,id,ans;  int pos;}q[200010];bool cmp1(query a,query b){  return a.pos<b.pos||(a.pos==b.pos&&a.r<b.r);}bool cmp2(query a,query b){  return a.id<b.id;}void init(){  scanf("%d",&n);  for(int i=1;i<=n;i++)    scanf("%d",&a[i]);  scanf("%d",&m);  int block=(int)sqrt((double)n+0.5);  for(int i=1;i<=m;i++)  {    scanf("%d%d",&q[i].l,&q[i].r);q[i].id=i;q[i].pos=(q[i].l-1)/block;  }  sort(q+1,q+m+1,cmp1);}void transfer(int p,int &ans,int add){  bool flag=0;  if (f[a[p]]==0) flag=1;  f[a[p]]+=add;  if (flag&&f[a[p]]>0) ans++;  else if (f[a[p]]==0) ans--;}void solve(){  int l=1,r=0,ans=0;  for(int i=1;i<=m;i++)  {    if (r<q[i].r) while(r<q[i].r) r++,transfer(r,ans,1);if (q[i].l<l) while(q[i].l<l) l--,transfer(l,ans,1);if (r>q[i].r) while(r>q[i].r) transfer(r,ans,-1),r--;if (q[i].l>l) while(q[i].l>l) transfer(l,ans,-1),l++;q[i].ans=ans;  }  sort(q+1,q+m+1,cmp2);  for(int i=1;i<=m;i++)    printf("%d\n",q[i].ans);}int main(){  init();  solve();    return 0;}


0 0
原创粉丝点击