很清新自然凶猛的数据结构题,都是套路啊
我们可以考虑离线做,先把区间按右端点从小到大排序
首先注意到一种贝壳如果在一段中出现超过1次,那么它在前面或后面就无关紧要了
举一个例子:
对于数列1 2 3 1如果我的右端点已经扫描到第四位了,那么第一位的1就可以删掉了(因为按右端点排了序)
所以我们开树状数组维护一个位置上是否有有效的颜色,即对于上一个例子2,3,4位上是有有效的颜色的
然后对于每一个操作,我们求出x,y这段区间内1的个数即可,树状数组减一发即可
具体看代码
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=500005,M=200005,MAX_NUM=1000005;
struct ques
{
int x,y,num;
}q[M];
int tree[N],a[N],num[MAX_NUM],ans[M],n,m,now;
inline char tc(void)
{
static char fl[100000],*A=fl,*B=fl;
return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
x=0; char ch=tc();
while (ch<'0'||ch>'9') ch=tc();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc();
}
inline void write(int x)
{
if (x/10) write(x/10);
putchar(x%10+'0');
}
inline bool comp(ques a,ques b)
{
return a.y<b.y;
}
inline int lowbit(int x)
{
return x&(-x);
}
inline void add(int x,int y)
{
while (x<=n)
{
tree[x]+=y;
x+=lowbit(x);
}
}
inline int get(int x)
{
int tot=0;
while (x)
{
tot+=tree[x];
x-=lowbit(x);
}
return tot;
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
register int i;
for (read(n),i=1;i<=n;++i)
read(a[i]);
for (read(m),i=1;i<=m;++i)
read(q[i].x),read(q[i].y),q[i].num=i;
sort(q+1,q+m+1,comp);
for (now=1,i=1;i<=m;++now)
{
if (!num[a[now]]) add(now,1),num[a[now]]=now; else add(num[a[now]],-1),num[a[now]]=now,add(now,1);
while (now==q[i].y&&i<=m)ans[q[i].num]=get(q[i].y)-get(q[i].x-1),++i;
}
for (i=1;i<=m;++i)
write(ans[i]),putchar('
');
return 0;
}