1878: [SDOI2009]HH的项链
Time Limit: 4 Sec Memory Limit: 64 MBSubmit: 2696 Solved: 1353
[ Submit][ Status][ Discuss]
Description
Input
Output
Sample Input
1 2 3 4 3 5
3
1 2
3 5
2 6
Sample Output
2
4
HINT
对于20%的数据,N ≤ 100,M ≤ 1000;
对于40%的数据,N ≤ 3000,M ≤ 200000;
对于100%的数据,N ≤ 50000,M ≤ 200000。
解题思路:首先想到线段树,但是空间太小,想来想去,只能离线,然后树状数组,
记入下每个数在序列中对应的所有位置。
对讯问按照起点排序。用tail来当做原数组的指针。如果tail<start[i]就要剪掉之间
所有数,在维护后一个同样数所在的位置(树状数组)。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int n,ans,q,len;
int a[51000],messi[51000];
struct ss
{
int x,y,dui;
}g[210000];
int zhong[1100001],to[51000],h[1100001],next[51000];
int sum[210000];
inline int read()
{
char y; int x=0,f=1; y=getchar();
while (y<'0' || y>'9') {if (y=='-') f=-1; y=getchar();}
while (y>='0' && y<='9') {x=x*10+int(y)-48; y=getchar();}
return f*x;
}
bool cmp(ss xg,ss yg)
{
return xg.x<yg.x;
}
void add(int now,int zhi)
{
while (now<=n)
{
messi[now]+=zhi;
now+=now&-now;
}
}
int query(int o)
{
int sum=0;
while (o>0)
{
sum+=messi[o];
o-=o&-o;
}
return sum;
}
void insert(int x,int y)
{
++len;
to[len]=y; next[len]=h[x]; h[x]=len;
}
int main()
{
n=read();
for (int i=1;i<=n;++i)
{
a[i]=read();
if (zhong[a[i]]==0)
{
add(i,1);
}
++zhong[a[i]];
}
for (int i=n;i>=1;--i)
{
insert(a[i],i);
}
q=read();
for (int i=1;i<=q;++i)
{
g[i].x=read(); g[i].y=read(); g[i].dui=i;
}
sort(g+1,g+q+1,cmp);
int tail=1;
for (int i=1;i<=q;++i)
{
while (tail<g[i].x)
{
add(tail,-1);
h[a[tail]]=next[h[a[tail]]];
if (h[a[tail]]!=0)
{
add(to[h[a[tail]]],1);
}
++tail;
}
sum[g[i].dui]=query(g[i].y)-query(g[i].x-1);
}
for (int i=1;i<=q;++i)
{
printf("%d\n",sum[i]);
}
}