题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1878
思路:参考了http://blog.csdn.net/njlcazl/article/details/8758443
下面加一些自己的理解:
因为操作中只有询问没有更新,所以可以使用离线算法,对所有询问按右区间升序排序。
以该数字第一次在区间中出现的点代表所有的点。如果是第一次出现,那么该数字 在之前从未出现或上一次出现不再区间内。
记录每个位置i的数字的前一个相同数字出现的位置pre[i],没有前一个相同的pre[i]为0。
然后从前到后扫描询问,每次将上一个同值点的值加1,然后求当前区间的左界的前缀和就是答案了。将当前位置下个位置的值减1,这样做可以保证任意一个数字在任意一段区间中最多出现一次。
代码中注释位置及下一行+1的原因是树状数组的第一个元素只能从1开始,不能从0开始。
下面给出我的两段代码,其中第二段是将pre[]归算到1开始计数的,避免了树状数组处理时+1的问题,较第一段代码注释处有更改。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1000010;
int n;
struct Node
{
int id,x,y;
bool operator < (const Node &b) const
{
return y<b.y;
}
}ask[N];
int last[N],pre[N],ans[N];
int bit[N];
int lowbit (int x)
{
return x&(-x);
}
void Update (int k,int x)
{
while (k<=n)
{
bit[k]+=x;
k+=lowbit(k);
}
}
int Getsum (int k)
{
int sum=0;
while (k>0)
{
sum+=bit[k];
k-=lowbit(k);
}
return sum;
}
int main ()
{
int i,q,temp;
scanf("%d",&n);
for (i=1;i<=n;++i)
{
scanf("%d",&temp);
pre[i]=last[temp];
last[temp]=i;
}
scanf("%d",&q);
for (i=0;i<q;++i)
{
scanf("%d%d",&ask[i].x,&ask[i].y);
ask[i].id=i;
}
sort(ask,ask+q);
int now=0;
for (i=0;i<q;i++)
{
while (now<ask[i].y)
{
++now;
Update (pre[now]+1,1); //树状数组从1开始
Update (now+1,-1);
}
ans[ask[i].id]=Getsum(ask[i].x);
}
for (i=0;i<q;i++)
printf("%d\n",ans[i]);
return 0;
}
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1000010;
int n;
struct Node
{
int id,x,y;
bool operator < (const Node &b) const
{
return y<b.y;
}
}ask[N];
int last[N],pre[N],ans[N];
int bit[N];
int lowbit (int x)
{
return x&(-x);
}
void Update (int k,int x)
{
while (k<=n+1) //
{
bit[k]+=x;
k+=lowbit(k);
}
}
int Getsum (int k)
{
int sum=0;
while (k>0)
{
sum+=bit[k];
k-=lowbit(k);
}
return sum;
}
int main ()
{
int i,q,temp;
scanf("%d",&n);
for (i=1;i<=n;++i)
{
scanf("%d",&temp);
pre[i]=last[temp]+1; //
last[temp]=i;
}
scanf("%d",&q);
for (i=0;i<q;i++)
{
scanf("%d%d",&ask[i].x,&ask[i].y);
ask[i].id=i;
}
sort(ask,ask+q);
int now=1; //
for (i=0;i<q;i++)
{
while (now<=ask[i].y)
{
++now;
Update (pre[now-1],1); //
Update (now,-1); //
}
ans[ask[i].id]=Getsum(ask[i].x);
}
for (i=0;i<q;i++)
printf("%d\n",ans[i]);
return 0;
}