莫队算法:
利用莫队算法对区间询问,进行离线操作真的很方便,但是这题数据量有点大,做不了,听说数据加强了,但是还是利用莫队来搞一发,只有60分
TLE莫队代码:
#include<bits/stdc++.h>
using namespace std;
//莫队算法
//求区间种类
const int maxn=1e6+1000;
struct node
{
int l,r,k;
} q[maxn];
int pos[maxn],a[maxn],kind[maxn];
bool cmp(node x,node y)
{
if(pos[x.l]==pos[y.l])
{
return x.r<y.r;
}
return pos[x.l]<pos[y.l];
}
int ans[maxn],res;
void add(int i)
{
if(!kind[a[i]])
res++;
kind[a[i]]++;
}
void sub(int i)
{
--kind[a[i]];
if(!kind[a[i]])
res--;
}
int main()
{
int n;
scanf("%d",&n);
int dis=sqrt(n);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
//kind[a[i]]=1;
pos[i]=i/dis;//分块
}
int m;
scanf("%d",&m);
for(int i=0; i<m; i++)
{
scanf("%d %d",&q[i].l,&q[i].r);
q[i].k=i;
}
sort(q,q+m,cmp);
int l=1,r=0;
for(int i=0; i<m; i++)
{
while(l<q[i].l)
{
sub(l++);
}
while(r>q[i].r)
{
sub(r--);
}
while(l>q[i].l)
{
add(--l);
}
while(r<q[i].r)
{
add(++r);
}
ans[q[i].k]=res;
}
for(int i=0; i<m; i++)
{
printf("%d\n",ans[i]);
}
}
数状数组解法:
离线对区间进行操作,如果某个位置在之后的位置也有出现,那么将之前的位置减去,之后的位置加1,删除之前的对之后的影响,我们将要询问的区间对r区间进行排序,从后往前,不会造成影响
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int c[maxn],n,a[maxn],last[maxn],pre[maxn],ans[maxn];
struct node
{
int l,r,k;
} q[maxn];
bool cmp(node x,node y)
{
return x.r<y.r;
}
int lowbit(int x)
{
return (x)&(-x);
}
void modify(int i,int k)
{
if(i==0)
return;
while(i<=n)
{
c[i]+=k;
i+=lowbit(i);
}
}
int getsum(int i)
{
int res=0;
while(i>0)
{
res+=c[i];
i-=lowbit(i);
}
return res;
}
int main()
{
scanf("%d",&n);
memset(pre,0,sizeof(pre));
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
pre[i]=last[a[i]];
last[a[i]]=i;
}
int m;
scanf("%d",&m);
for(int i=1; i<=m; i++)
{
scanf("%d %d",&q[i].l,&q[i].r);
q[i].k=i;
}
sort(q+1,q+1+m,cmp);
// for(int i=1; i<=m; i++)
// {
// printf("%d %d\n",q[i].l,q[i].r);
// }
int r=0;
for(int i=1; i<=m; i++)
{
//cout<<1;
while(r<q[i].r)
{
r++;
modify(pre[r],-1);
modify(r,1);
//printf("%d\n",1);
}
ans[q[i].k]=getsum(q[i].r)-getsum(q[i].l-1);
}
for(int i=1; i<=m; i++)
{
printf("%d\n",ans[i]);
}
}